【问题标题】:Rails routes: GET without param :idRails 路线:GET 没有参数 :id
【发布时间】:2013-06-08 15:10:57
【问题描述】:

我正在开发一个基于 rails 的 REST api。要使用此 api,您必须登录。关于这一点,我想在我的用户控制器中创建一个方法 me,它将返回登录用户信息的 json。 所以,我不需要在 URL 中传递 :id。我只想打电话给http://domain.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 的东西。示例如下:

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

在此示例中,您可以编辑当前用户密码,而无需将 id 作为参数传递。

我可以使用集合而不是成员,但这是一个肮脏的绕过...

有人有想法吗? 谢谢

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-3.2 routes


    【解决方案1】:

    要走的路是使用singular resources:

    所以,不要使用resources,而是使用resource

    有时,您有一个资源,客户端总是在不引用 ID 的情况下查找该资源。例如,您希望 /profile 始终显示当前登录用户的个人资料。在这种情况下,您可以使用单一资源将 /profile(而不是 /profile/:id)映射到显示操作 [...]

    所以,在你的情况下:

    resource :user do
      get :me, on: :member
    end
    
    # => me_api_user GET    /api/users/me(.:format)            api/v1/users#me {:format=>"json"}
    

    【讨论】:

    • 太好了,这让我的路由文件变得简单了很多。
    • 这应该被接受。虽然get 'users/me' => 'users#me' 工作得很好,但将它们分组为单一资源是一种更简洁的方法。
    • 请务必注意红色方框中提到的关于单一资源的长期存在的错误。 github.com/rails/rails/issues/1769
    • 我认为如果您定义了resources,那么添加到collection 会更好(正如其他一些答案所指出的那样)。添加单个资源会起作用,但我认为将它们放在一起会更有意义且更具可读性
    • 注意:应该使用单数 resource 或复数 resources 但不要组合它们,否则只会将第一个匹配项路由到。
    【解决方案2】:

    资源路由旨在以这种方式工作。如果您想要不同的东西,请自己设计,就像这样。

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

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

    【讨论】:

    • 出色的阿扬。正是我需要的……除了我没有路径但我可以没有它。干杯。
    • 没问题,你可以通过添加:as => 'me'来添加路径。这将添加me_pathme_url
    • 考虑使用单一资源作为answer
    【解决方案3】:

    你可以使用

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

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

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

    【讨论】:

      【解决方案4】:

      也许我错过了什么,但你为什么不使用:

      get 'me', on: :collection
      

      【讨论】:

      • 这就是我在结论中所说的。这不是一个很好的解决方法,因为集合是多个对象的数组。我要的是 current_user,所以 1 个对象,所以是成员 ;-)
      【解决方案5】:
        resources :users, only: [:index, :update] do
          collection do
            get :me, action: 'show' 
          end
        end
      

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

      【讨论】:

        【解决方案6】:

        这以更简单的方式给出了与 Arjan 相同的结果

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

        【讨论】:

          【解决方案7】:

          当您创建嵌套在资源中的路由时,您可以提及它是成员操作还是集合操作。

          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
          ...
          ...
          

          【讨论】:

          • 这就是我在结论中所说的。这不是一个很好的解决方法,因为集合是多个对象的数组。我要的是 current_user,所以 1 个对象,所以是成员 ;-)
          猜你喜欢
          • 1970-01-01
          • 2014-07-02
          • 2014-12-11
          • 2017-08-03
          • 2017-05-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-10-04
          相关资源
          最近更新 更多