Help us understand the problem. What is going on with this article?

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

More than 5 years have passed since last update.

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

heartrails
ハートレイルズは、新規事業の立ち上げに伴うウェブサービス、スマホアプリの企画、開発、運用に特化した開発会社です。
http://www.heartrails.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away