LoginSignup
509
487

More than 5 years have passed since last update.

resources を nest するときは shallow を使うと幸せになれる

Last updated at Posted at 2012-09-20

scaffold を制するものは rails を制す、という言い伝えがありますが、 rails g scaffold User などとすると routes.rb に突如現れるのが、 resources というやつです。

いまここに、Group と User という2つのモデルがあり、 Group が has_many :users で、 User が belongs_to :group だとしましょう。よくある関係ですね。

このような場合に、resources を

config/routes.rb
resources :group do
  resources :user
end

こんな風に nest すると、新規に User を作る時の URL が /groups/:group_id/users/new となり、自然な形で group_id を渡すことができます。

ところが、このように routes を定義すると、いざ User が生成された後にその User を show するには /groups/:group_id/users/:id などとしなければならなくなってしまいます。
これは冗長ですね。 User の id が group に寄らず unique であるなら、 /users/:id で参照出来て然るべきです。

そこで、shallow です。

config/routes.rb

resources :group, shallow: true do
  resources :user
end

こうすると、なんと、

# rake routes
 group_user_index GET    /group/:group_id/user(.:format)          user#index
                  POST   /group/:group_id/user(.:format)          user#create
   new_group_user GET    /group/:group_id/user/new(.:format)      user#new
        edit_user GET    /user/:id/edit(.:format)                 user#edit
             user GET    /user/:id(.:format)                      user#show
                  PUT    /user/:id(.:format)                      user#update
                  DELETE /user/:id(.:format)                      user#destroy
      group_index GET    /group(.:format)                         group#index
                  POST   /group(.:format)                         group#create
        new_group GET    /group/new(.:format)                     group#new
       edit_group GET    /group/:id/edit(.:format)                group#edit
            group GET    /group/:id(.:format)                     group#show
                  PUT    /group/:id(.:format)                     group#update
                  DELETE /group/:id(.:format)                     group#destroy

な、なんて美しいんだ。。!

何が起きているかというと、user_id を指定しない action である index, new, create の3つは group_id を必要とし、それ以外の action では user_id のみを指定すればよい、ということに、たったの "shallow: true" だけでなってしまったのです。

もちろん、以下のように action を拡張した場合

config/routes.rb

resources :group, shallow: true do
    resources :user do
      get :search, on: :collection
      post :follow, on: :member
    end
end

には、

# rake routes
(抜粋)
search_group_user_index GET    /group/:group_id/user/search(.:format)   user#search
            follow_user POST   /user/:id/follow(.:format)               user#follow

ご覧の通り、 on: :collection で定義した :search の方にのみ、:group_id が必須になっています。
そうですそうです、そうして欲しかったんですよ!

さらに深く resources を nest した場合にも、 shallow:true は1つだけで大丈夫。

config/routes.rb

resources :group, shallow:true do
  resources :user do
    resources :entry
  end
end

この場合、entries#new は /user/:id/entries/new となり、 entries#show は /entries/:id となります。

最後に、おそらく多くの方が form でつまずくと思うので、その時はこれを読みましょう: http://stackoverflow.com/a/9944554/683157

Author: kuboon

509
487
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
509
487