如何在Rails中为具有多个关键字段的资源定义RESTful路由?

时间:2009-03-02 21:25:58

标签: ruby-on-rails resources rest primary-key routes

我的用户模型具有通常的id主键,但它也有唯一的login,可用作标识符。因此,我想定义路由,以便可以通过id或登录访问用户。理想情况下,路线将是这样的:

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

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

这样做的最佳方法是什么(或类似的东西)?

4 个答案:

答案 0 :(得分:1)

到目前为止,我能想到的最好的是:

map.resources :users

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

为用户创建了常用的RESTful路由,最重要的是,users_by_login资源添加了以下路由(仅限于那些路径):

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

这些路线实际上也映射到UserController(仅适用于show / edit / update / destroy方法)。添加了额外的by_login参数(等于true):这样,UserController方法可以判断id参数是表示登录还是id。

它完成了这项工作,但我希望有更好的方法。

答案 1 :(得分:1)

只需检查传递给控制器​​方法的ID是否为整数。

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

无需添加特殊路线。

答案 2 :(得分:1)

实际上Kyle Boon在这里有正确的想法。但它有点偏。当params变量出现时,所有值都存储为字符串,因此他的示例每次都会返回false。你能做的是:

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

这样,如果:id是一个实际的字符串Ruby只是将它转换为0.你可以通过使用ruby-debug gem查看params hash来测试它。

(我刚刚评论过,但我没有足够的经验来做到这一点;)

答案 3 :(得分:0)

不完全确定你在这里做了什么,但这可能会有所帮助。

您可以通过添加:member or :collection选项来定义rails提供的自动RESTful路由之外的操作。

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

这将生成如下所示的路线:

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

你可以做的另一件事就是使用login作为你查找的属性(假设它是唯一的)。查看Ryan Bates screencast。在您的控制器中,您将拥有:

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

他还有另一个screencast可以帮到你。第二个讨论自定义命名路由。