🤔

【Rails】 ルーティングのnamespace, module, scopeの違い

2023/01/23に公開約2,200字

この話題は結論から書いてもわかりにくくなると思ったので、順を追って整理する。

たとえば、こんなルーティングがあったとする。

 resources :books, only: :show do
   resources :reviews, only: :index
 end

これは、以下のURLとコントローラー#アクションになる。(only: :indexの書き方の流派などはプロジェクトごとに変わると思うので気にせず)

  • URL:/books/:book_id/reviews
  • Controller#Action:reviews#index

だが、これでは「すべてのreviewsを表示する」という仕様があったとき、reviews#indexが使われてるので被ってしまいそうだ。

ここでnamespaceを使うとどうなるか?

  resources :books, only: :show do
    namespace :books do
      resources :reviews, only: :index
    end
  end

コントローラーとアクションはbooks/reviews#indexとなり、ファイル構成もbooks/reviews_controller.rbと名前空間を分けられる。

しかし、肝心のURLが/books/:book_id/books/reviewsとおかしくなってしまう。

namespaceを使った場合:

  • URL:/books/:book_id/books/reviews(※意味不明なURL)
  • Controller#Action:books/reviews#index

このように、namespaceはURLでも、Controller#Action(つまりファイル構成)でもスコープを分ける。

「URLは変えずに、Controller#Actionは分けたい(ファイル構成だけでスコープを分けたい)」というときに使えるのがmoduleオプションだ。

  resources :books, only: :show do
-   resources :reviews, only: :index
+   resources :reviews, only: :index, module: :books
  end

こうすれば、

  • URL:/books/:book_id/reviews
  • Controller#Action:books/reviews#index

となり、よい感じになる。

ちなみに、moduleオプションはscope moduleブロックを使っても書ける。

  resources :books, only: :show do
    scope module: 'books' do
      resources :reviews, only: :index
      #他のリソースもDRYに書いていける
    end
  end

こうすることで、reviews以外のリソースがあったときもいちいちmodule: :booksを書かなくてよくなる。
Rubyでmoduleを使って名前空間を作るように、routes.rb内でmoduleオプションを使って名前空間を作れるというイメージで覚えるのが個人的にはしっくりくる。

ただ、scopescope module:は似たような記述だが違う挙動になるので注意が必要だ。

  resources :books, only: :show do
    scope 'books' do # scope moduleではなくscopeだけにしたら...
      resources :reviews, only: :index
    end
  end
  • URL:/books/books/:book_id/reviews(URLとしておかしい)
  • Controller#Action:reviews#index(他のと被っちゃいそう)

scopemoduleオプションの反対で、Controller#Actionに影響はないが、URLが変わる。

namespce, module, scopeの使い方まとめ

それぞれの用途をまとめると、

  • namespace: URLとファイル構成でスコープを分けたい
  • module(scope module:):ファイル構成だけでスコープを分けたい
  • scope: URLだけでスコープを分けたい

となる。

Rails のルーティング - Railsガイドにはもっとわかりやすい説明があるので、全体に目を通しておくことをおすすめします。

Discussion

ログインするとコメントできます