Ruby
Rails

/users/passwordみたいな、URLのネストしたリソースに親IDを入れないroutesの書き方

More than 3 years have passed since last update.

なんか毎回忘れたころに書くことになってその度にググってるので、書き留めておく。

resourcesresourceを直接ネストさせると、親のuser_idがURLに入る。

routes.rb
resources :users, only: %i() do
  resource :password, only: %i(update)
end
% rake routes
user_password PATCH /users/:user_id/password(.:format) passwords#update
              PUT   /users/:user_id/password(.:format) passwords#update

UserPasswordのようなリクエストユーザが自身のリソースのみにアクセスできるような親子パターンでは、リクエストしたユーザ自身のuser_id以外を指定できるようなURLはパラメータが無意味になるだろうし、user_idはURLパスから取り除きたい。

アクションメソッドをusers_contorller.rbに書いてしまうパターン。

routes.rb
resources :users, only: %i() do
  patch :password, on: :collection
end

# or

resources :users, only: %i() do
  collection do
    patch :password
  end
end
% rake routes
password_users PATCH /users/password(.:format) users#password

しかし、この方法だとuserリソースのためのメソッドとコンフリクトしないために、大抵のパターンで:edit_password:update_passwordなどのルートを作ることになりアクションの名前にいびつさが出てくる。

別のコントローラファイルを作って親と同じくscaffoldパターンのアクションを追加したい。

routes.rb
resources :users, only: %i() do
  collection do
    resource :password, only: %i(edit update)
  end
end
% rake routes
edit_password GET   /users/password/edit(.:format) passwords#edit
     password PATCH /users/password(.:format)      passwords#update
              PUT   /users/password(.:format)      passwords#update

コントローラファイルのパスもURLと合わせたいので、さらにcontrollerもしくはtoオプションを追加する。

routes.rb
resources :users, only: %i() do
  collection do
    resource :password, only: %i(edit update), controller: 'users/password'
  end
end
% rake routes
edit_password GET   /users/password/edit(.:format) users/password#edit
     password PATCH /users/password(.:format)      users/password#update
              PUT   /users/password(.:format)      users/password#update