Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails 3.0: error with routes when overriding to_param in model

I'm getting an error with my routes when I try to override to_param in my user model to use the email address as the id. It appears to be trying to match the entire object for the id when it tries to match the route. Can anyone help me figure out what I'm missing?

Here's the error:

No route matches {:controller=>"users", :action=>"show", :id=>#<User id: 1, email: ....>}

Here's how I've set up the code.

models/user.rb:

attr_accessible :email    

def to_param 
  email
end

controllers/users_controller.rb:

before_filter :get_user, :only=>[:show,:update,:edit,:destroy]

...

def get_user
  @user = User.find_by_email params[:id]
end

config/routes.rb

resources :users

And here's the output from rake routes:

     user GET    /users(.:format)          {:controller=>"users", :action=>"index"}
          POST   /users(.:format)          {:controller=>"users", :action=>"create"}
 new_user GET    /users/new(.:format)      {:controller=>"users", :action=>"new"}
edit_user GET    /users/:id/edit(.:format) {:controller=>"users", :action=>"edit"}
     user GET    /users/:id(.:format)      {:controller=>"users", :action=>"show"}
          PUT    /users/:id(.:format)      {:controller=>"users", :action=>"update"}
          DELETE /users/:id(.:format)      {:controller=>"users", :action=>"destroy"}
like image 688
Bee Avatar asked Feb 11 '11 22:02

Bee


2 Answers

The problem is that the email adds a '.' (dot) in the url, and that confuses rails, because it tries to find a "com" format (if the email ends in .com)

I've added this code to one of my apps (I have People instead of Users) and it works properly, so the trick is to replace the dot with something else. I chose to replace it with an '@' as other symbols such as - or + are valid in email addresses.

file person.rb

def to_param
  email.sub ".", "@"
end

def self.param_to_email(param) 
  segments = param.split '@'
  host = segments[1..-1].join('.')
  segments[0] + '@' + host
end

file people_controller.rb

def get_person
  email = Person.param_to_email params[:id]
  @person = Person.find_by_email email
end

There are some more hints about how this works in http://jroller.com/obie/entry/seo_optimization_of_urls_in.

Thanks for the question, I'm just starting with rails, so this is really helping me to understand how it works :).

like image 113
Augusto Avatar answered Oct 07 '22 06:10

Augusto


You can include dots '.' in your to_param return value if you specify a custom regular expression for the 'id' parameter in your route, for example:

match '/images/:id',
  :via => :get,
  :constraints => { :id => /[^\/]+/ },
  :format => false,
  :to => 'images#show',
  :as => :image

See http://edgeguides.rubyonrails.org/routing.html#specifying-constraints for more details.

like image 33
Sam Umbach Avatar answered Oct 07 '22 06:10

Sam Umbach