How to define RESTful routes in Rails for a resource with several key fields?

My user model has a regular id primary key, but also has a unique login , which can be used as an identifier. Therefore, I would like to define routes so that users can access either by identifier or by login. Ideally, the routes would be something like this:

 /users/:id (GET) => show (:id) /users/:id (PUT) => update (:id) ... /users/login/:login (GET) => show (:login) /users/login/:login (PUT) => update (:login) ... 

What is the best way to do this (or something similar)?

+4
source share
4 answers

So far, the best I could come up with is this:

 map.resources :users map.resources :users_by_login, :controller => "User", :only => [:show, :edit, :update, :destroy], :requirements => {:by_login => true} 

Regular RESTful routes are created for users, and in addition, the users_by_login resource adds the following routes (and only those):

 GET /users_by_login/:id/edit GET /users_by_login/:id/edit.:format GET /users_by_login/:id GET /users_by_login/:id.:format PUT /users_by_login/:id PUT /users_by_login/:id.:format DELETE /users_by_login/:id DELETE /users_by_login/:id.:format 

These routes are actually displayed in the UserController ( show / edit / update / destroy methods only). An additional by_login parameter (equal to true ) has been added: in this way, the UserController methods can determine whether the id parameter specifies a login or identifier.

He does the job, but I want a better way.

+1
source

Just check if the identifier passed to the controller methods is an integer.

 if params[:id].is_a?(Integer) @user = User.find params[:id] else @user = User.find_by_login params[:id] 

No need to add special routes.

+1
source

In fact, Kyle Boone has the right idea. But it is a little off. When params is included in all values, they are stored as strings, so its example returns false every time. What you can do is:

 if params[:id].to_i.zero? @user = User.find_by_login params[:id] else @user = User.find params[:id] end 

Thus, if: id is the actual string, Ruby simply converts it to 0. You can check this by looking at the params hash parameters using the ruby-debug stone.

(I would just comment, but I don't have enough experience to do this;)

+1
source

Not quite sure what you are doing here, but it might help.

You can define actions that are outside of the RESTful automatic routes that the rails provide by adding the : member or: collection parameter.

 map.resources :users, :member => { :login => [:post, :get] } 

This will create routes that look like this:

 /users/:id (GET) ... /users/:id/login (GET) /users/:id/login (POST) 

Another thing is that you can use the login as the attribute you are looking for (provided that it is unique). Look at him Ryan Bates screencast . In your controller you will have:

 def show @user = User.find_by_login(params[:id]) ... end 

It also has another screencast that can help you. The second is about user routes.

0
source

All Articles