Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails REST routing: dots in the resource item ID

I have following in my routes.rb:

resources :users, :except => [:new, :create] do
    get 'friends', :as => :friends, :on => :member, :to => "users#friends"
end

and following in my user.rb:

def to_param
  self.login
end

And when, for example, user with dots in login (for example 'any.thing') comes from facebook, rails gives routing error (no route found, I suppose that's because it recognises anything after dot as a format or because of route constraints). How can I come over this error?

like image 875
sandrew Avatar asked Mar 07 '11 17:03

sandrew


People also ask

How do I see routes in Rails?

TIP: If you ever want to list all the routes of your application you can use rails routes on your terminal and if you want to list routes of a specific resource, you can use rails routes | grep hotel . This will list all the routes of Hotel.

What is resources in routes RB?

Resource routing allows you to quickly declare all of the common routes for a given resourceful controller. A single call to resources can declare all of the necessary routes for your index , show , new , edit , create , update , and destroy actions.

What are resources in Rails routes?

Any object that you want users to be able to access via URI and perform CRUD (or some subset thereof) operations on can be thought of as a resource. In the Rails sense, it is generally a database table which is represented by a model, and acted on through a controller.

What are RESTful routes in Rails?

3.2 CRUD, Verbs, and Actions In Rails, a RESTful route provides a mapping between HTTP verbs, controller actions, and (implicitly) CRUD operations in a database. A single entry in the routing file, such as. map.resources :photos. creates seven different routes in your application: HTTP verb.


2 Answers

The following constrain definition permit the dot in id as well as any character except slash.

Supported formats must be explicitly defined (here .html and .json) to not to be taken by id.

resources :foobars,
  :constraints => { :id => /[^\/]+(?=\.html\z|\.json\z)|[^\/]+/ }

That constrain definition is worked with Rails 3.1

For earlier Rails versions you may need to backport look-ahead support in regin gem (it is vendored in rack-mount gem)

like image 124
senotrusov Avatar answered Sep 25 '22 01:09

senotrusov


You could replace periods with another character:

def to_param
  login.gsub(/\./,"-") # note: 'self' is not needed here
end

user = User.find_by_login("bart.simpson")
user_path(user) # => "/users/bart-simpson"

EDIT

You're right, this fails to deal with unique logins that map to the same value. Maybe a better way is to use segment constraints in the route:

  match 'users/(:id)' => 'users#show', 
    :constraints => { :id => /[0-9A-Za-z\-\.]+/ }

This should allow "/users/bart-simpson" and /users/bart.simpson" to generate :id => "bart-simpson" and :id => "bart.simpson" respectively. You'd have to alter the regex to add all the acceptable characters for the URL.

Note that this is mentioned in the Rails Routing Guide, section 3.2:

By default dynamic segments don’t accept dots – this is because the dot is used as a separator for formatted routes. If you need to use a dot within a dynamic segment add a constraint which overrides this – for example :id => /[^\/]+/ allows anything except a slash.

like image 28
zetetic Avatar answered Sep 25 '22 01:09

zetetic