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"}
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 :).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With