Rails 3 Routes Configuration – Dynamic Segments, Constraints and Scope

I’ve been messing around with Rails for the past few months, and I just got through figuring this out so I thought I’d post this here.

Sometimes you want to have a dynamic segment in a route. For example: /:username, to allow your users to have vanity urls. You might use something like this:

  get '/:username' => 'profiles#show'

However, you obviously don’t want routes like /login or /logout to be routed to your controller (in the above case, the profiles controller). In this case we would use segment constraints. Rails allows you to use either a regular expression as shown in this rails guide on segment constraints.

The other method is to use a Constraint class:

  get '/:username' => 'profiles#show', :constraints => ProfileConstraint

Reference the ProfileConstraint class by creating a new directory/file called app/constraints/profile_constraint.rb:

class ProfileConstraint
  def self.matches?(request)
    reserved_words = ['login', 'signup', 'signout', 'welcome', 'home']
    !reserved_words.include?(request.path_parameters[:username])
  end
end

Above, Rails looks for the matches? method in ProfileConstraint sends it a request object, which we then use to decide whether to match the route or not by comparing it against an array of reserved_words.

Another useful way to add on to the above would be to use scope. This allows you to extend your route like /:username/comments:

scope '/:username', :constraints => ProfileConstraint do
  get '' => 'profiles#show'
  get '/comments' => 'profile#comments'
end

And now you’ll have routes like so:

          GET        /:username(.:format)                   {:controller=>"profiles", :action=>"show"}
following GET        /:username/comments(.:format)         {:controller=>"profiles", :action=>"comments"}

Hope someone finds this useful as I did.

Tips for improving:
- Dynamically add model/controller classnames and routes to the reserved_words array.

This entry was posted in Uncategorized. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

One Comment

  1. KG
    Posted January 16, 2012 at 5:26 pm | Permalink

    thanks for this. I was previously using get instead of scopes in my routes. well done brobotslacker.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>