Rails路由:不带参数:id的GET请求

52

我正在基于Rails开发一个REST API。要使用此API,您必须先登录。因此,我想在用户控制器中创建一个名为me的方法,以返回已登录用户信息的JSON格式数据。

所以,我不需要在URL中传递:id。我只需要调用http://example.com/api/users/me

于是我尝试了这个:

namespace :api, defaults: { format: 'json' } do
  scope module: :v1, constraints: ApiConstraints.new(version: 1, default: true) do
    resources :tokens, :only => [:create, :destroy]
    resources :users, :only => [:index, :update] do

      # I tried this
      match 'me', :via => :get
      # => api_user_me GET    /api/users/:user_id/me(.:format)       api/v1/users#me {:format=>"json"}

      # Then I tried this
      member do
        get 'me'
      end
      # => me_api_user GET    /api/users/:id/me(.:format)            api/v1/users#me {:format=>"json"}

    end
  end
end

正如您所看到的,我的路由等待一个id,但我希望得到像devise一样的东西。基于current_user id。以下是示例:

如上所述,我的路由需要等待一个ID参数,但我希望能够像Devise一样使用基于当前用户ID的方法。下面是一个示例:

edit_user_password GET    /users/password/edit(.:format)         devise/passwords#edit

在这个例子中,您可以编辑当前用户的密码而不需要将ID作为参数传递。

我可以使用集合而不是成员,但那是一个肮脏的绕过方式。

7个回答

125

使用单数资源是正确的方式:

因此,不要使用resources,而要使用resource

有时,您拥有的资源客户端总是查找而不参考ID。例如,您希望/profile始终显示当前登录用户的配置文件。在这种情况下,可以使用单数资源将/profile(而不是/profile/:id)映射到show操作[...]。

因此,在您的情况下:

resource :user do
  get :me, on: :member
end

# => me_api_user GET    /api/users/me(.:format)            api/v1/users#me {:format=>"json"}

1
太好了,这让我的路由文件变得简单多了。 - mc9
5
可以接受。虽然 get 'users/me' => 'users#me' 可以正常工作,但将它们作为单数资源组合是更清晰的方法。 - Orlando
请确保注意红框中提到的关于单一资源的长期存在的错误。https://github.com/rails/rails/issues/1769 - Kyle Heironimus
我认为如果你已经定义了“资源”,那么将其添加到“集合”中会更好(正如其他答案所指出的)。添加单个资源是可行的,但我认为将所有内容保持在一起会更有意义和更易读。 - doz87
1
注意:应该只使用单数的 resource 或者复数的 resources,而不是混合使用,否则只有第一个出现的会被路由到。 - weshouman

24

资源路由被设计成这样工作。如果你想要不同的东西,就像这样自己设计。

match 'users/me' => 'users#me', :via => :get

把它放在你的resources :users块的外面


太棒了,Arjan。正是我需要的...除了我没有路径,但我可以不用它。干杯。 - Gozup
没问题,你可以通过添加 :as => 'me' 来添加一个路径。这将添加 me_pathme_url - Arjan
1
考虑使用单数资源作为答案 - RPinel

21

您可以使用

resources :users, only: [:index, :update] do
  get :me, on: :collection
end

或者
resources :users, only: [:index, :update] do
  collection do
    get :me
  end
end

成员路由需要一个ID,因为它作用于一个成员对象。集合路由不需要,因为它作用于一组对象。预览是成员路由的一个例子,因为它作用于(并显示)单个对象。搜索是集合路由的一个例子,因为它作用于(并显示)一组对象。(来自这里)


14

也许我漏掉了什么,但为什么你不使用:

get 'me', on: :collection

这就是我在结论中所说的。这不是一个好的解决方法,因为集合是多个对象的数组。我正在寻找当前用户,所以只有一个对象,是成员;-) - Gozup

7
  resources :users, only: [:index, :update] do
    collection do
      get :me, action: 'show' 
    end
  end

指定操作是可选的。您可以在此跳过操作并将控制器操作命名为me


3

这个代码以更简单的方式获得与Arjan相同的结果

get 'users/me', to: 'users#me'


0

当您在资源内创建嵌套路由时,可以指定它是成员操作还是集合操作。

namespace :api, defaults: { format: 'json' } do
  scope module: :v1, constraints: ApiConstraints.new(version: 1, default: true) do
    resources :tokens, :only => [:create, :destroy]
    resources :users, :only => [:index, :update] do

      # I tried this
      match 'me', :via => :get, :collection => true
...
...

这就是我在结论中所说的。这不是一个好的解决方法,因为集合是多个对象的数组。我正在寻找当前用户,所以只有一个对象,是成员;-) - Gozup

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接