Rails routes: GET without param :id

2019-02-11 10:42发布

问题:

I'm developing a REST api based on rails. To use this api, you MUST be logged in. Regarding that, I'd like to create a method me in my user controller that will return a json of the logged in user infos. So, I don't need an :id to be passed in the URL. I just want to call http://domain.com/api/users/me

So I tried this:

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

As you can see, my route waits for an id, but I'd like to get something like devise has. Something based on current_user id. Example below:

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

In this example you can edit the current user password without passing the id as a param.

I could use a collection instead of a member, but that's a dirty bypass...

Anyone has an idea? Thank you

回答1:

Resource routes are designed to work this way. If you want something different, design it yourself, like this.

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

Put it outside of your resources :users block



回答2:

The way to go is to use singular resources:

So, instead of resources use resource:

Sometimes, you have a resource that clients always look up without referencing an ID. For example, you would like /profile to always show the profile of the currently logged in user. In this case, you can use a singular resource to map /profile (rather than /profile/:id) to the show action [...]

So, in your case:

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

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


回答3:

Maybe I am missing something, but why don't you use:

get 'me', on: :collection


回答4:

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

specifying the action is optional. you can skip action here and name your controller action as me.



回答5:

You can use

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

or

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

"A member route will require an ID, because it acts on a member. A collection route doesn't because it acts on a collection of objects. Preview is an example of a member route, because it acts on (and displays) a single object. Search is an example of a collection route, because it acts on (and displays) a collection of objects." (from here)



回答6:

When you create a route nested within a resource, you can mention, whether it is member action or a collection action.

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


回答7:

This gives same result as Arjan's in simpler way

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