0

Is there anyway to achieve friendly URLs for sinatra for e.g.,

I want the user to see http://xyz.io/username/title instead of http://xyz.io/username/posts/xdsfsdfsdfsd/title

but still route to the second URL.

Is there a of achieving this using Sinatra/Rack, or are there any ruby gems which does the job?

David Weiser
  • 5,190
  • 4
  • 28
  • 35

3 Answers3

2

Put the code that handles the request in a normal Ruby method, then simply have both routes call that method as their action.

def handle_request
   #params hash is available here as in normal route block
end

get '/:username/posts/:id/:title' do
  handle_request
end

get '/:username/:title' do
  handle_request
end
matt
  • 78,533
  • 8
  • 163
  • 197
  • I need the :id information from '/:username/posts/:id/:title' while wanting the user to see '/:username/:title' in his browser url bar, how else can this be achieved aren't there any friendly url gems for Sinatra like friendlyId (for RoR). – Arjun Variar May 21 '12 at 04:58
  • Matt, you answer is great, but having two URLs for the same content is bad, SEO-wise. @ArjunVariar I suggest keeping one single URL, the prettier. – Samy Dindane May 21 '12 at 08:28
  • @ArjunVariar if the user doesn’t enter the long url, you won’t have the `:id` value anyway. FriendlyId is an addition to active record, so if you want something like that, your solution will depend on how you’re storing the posts. You’ll need to be able to retrieve them by name rather than id. – matt May 21 '12 at 14:10
0

Option 1: Redirect from 'nice' URL to 'real' URL

get "/:user/:title" do
  user, title = params.values_at('user','title')
  id = find_id_from_title_and_user( user, title )
  redirect url("/#{user}/posts/#{id}/#{title}")
end

Option 2: Make the 'ugly' URL always look 'nice'

When the user loads the ugly URL, change the address bar—without reloading the page—to a prettier URL:

<!-- on the 'ugly' page -->
<script type="text/javascript">
  // Make the address bar lie about what our address is
  // See: https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history
  history.pushState({}, window.title, calculateNiceURLString());
</script>

Requires option 1 as well—or some handling of the 'nice' URL—for reload and bookmarking to work.

Phrogz
  • 296,393
  • 112
  • 651
  • 745
0

FriendlyId works with ActiveRecord, and activerecord is available for Sinatra. Follow this blog tutorial http://danneu.com/posts/15-a-simple-blog-with-sinatra-and-active-record-some-useful-tools/ to see how to get that going. What I did after that was put friendly_id in my gemfile, ran

bundle
rake db:create_migration NAME=add_slug_to_posts

Edit the newly created migration to look like

class AddSlugToPosts < ActiveRecord::Migration
    def change
        add_column :posts, :slug, :string
        add_index :posts, :slug, unique: true
    end
end

then run

rake db:migrate

AFTER that I required it in my app.rb file (require 'friendly_id'), and made sure I put these two lines at the top of my Post class

class Post < ActiveRecord::Base
    extend FriendlyId
    friendly_id :title, use: :slugged
...
end

Wherever I referenced :id in the url, params hash or anywhere, whether it be in app.rb or the links in views, I changed it to :slug. The slug is a unique identifier so it works fine. I already had some posts in the database, so I manually input slugs just by running tux then putting

a = Post.find(1)
a.save

(and changing the number) for each entry, and friendly_id automatically creates the slug. It will also create all the slugs on the creation of any new post. Beauty! btw my versions are

activerecord = 3.2.13
friendly_id = 4.0.9
ruby = 1.9.3
user462238
  • 43
  • 5