Madogiwa Blog

主に技術系の学習メモに使っていきます。

Ruby on Rails: Rails 6.1でroutes.rbを複数ファイルに分割する

以下のPRで導入されたRails 6.1から使える機能を使うといい感じでroutesを複数ファイルに分割できたのでやり方をメモしておきます📝

github.com

やり方

以下のようなroutesをnamespace毎に分割したいときには、

Rails.application.routes.draw do
  root to: 'boards#new'
  resources :feeds, only: [:index, :show, :new, :create]
  resources :boards, only: [:show, :new, :index], constraints: { format: :html }
  get '/boards/:id', to: 'rss/boards#show', constraints: lambda { |req| req.format == :rss }
  get '/mypage', to: 'mypage#show'

  namespace :api do
    resources :feeds, only: [:index, :show]
    resources :feed_entries, only: [:index], controller: 'feed/entries'
    resources :entries, only: [:index]
    resources :boards, only: [:create, :show, :index]
    resources :tags, only: [:index]
  end

  namespace :admin do
    root to: 'boards#index'
    resources :boards
    resources :board_feeds
    resources :feeds
    require 'sidekiq/web'
    mount Sidekiq::Web, at: '/sidekiq'
  end
end

以下のようにcoufig/routes配下にファイルを分けて、

# config/routes/admin.rb
Rails.application.routes.draw do
  namespace :admin do
    root to: 'boards#index'
    resources :boards
    resources :board_feeds
    resources :feeds
    require 'sidekiq/web'
    mount Sidekiq::Web, at: '/sidekiq'
  end
end
# config/routes/api.rb
Rails.application.routes.draw do
  namespace :api do
    resources :feeds, only: [:index, :show]
    resources :feed_entries, only: [:index], controller: 'feed/entries'
    resources :entries, only: [:index]
    resources :boards, only: [:create, :show, :index]
    resources :tags, only: [:index]
  end
end

config/routes.rbで以下のようにdraw :filenameとしてあげればOKです🙆‍♂️

Rails.application.routes.draw do
  root to: 'boards#new'
  resources :feeds, only: [:index, :show, :new, :create]
  resources :boards, only: [:show, :new, :index], constraints: { format: :html }
  get '/boards/:id', to: 'rss/boards#show', constraints: lambda { |req| req.format == :rss }
  get '/mypage', to: 'mypage#show'

  draw :api
  draw :admin
end

drawメソッドの中身は以下のような形になっていて、引数で渡されたfile名で探索して、instance_evalで分割したファイル内の処理を実行することで、分割したファイル内の処理をroutes.rbで実行することで、routesを定義しているようですね👀

# actionpack/lib/action_dispatch/routing/mapper.rb
        def draw(name)
          path = @draw_paths.find do |_path|
            File.exist? "#{_path}/#{name}.rb"
          end

          unless path
            msg  = "Your router tried to #draw the external file #{name}.rb,\n" \
                   "but the file was not found in:\n\n"
            msg += @draw_paths.map { |_path| " * #{_path}" }.join("\n")
            raise ArgumentError, msg
          end

          route_path = "#{path}/#{name}.rb"
          instance_eval(File.read(route_path), route_path.to_s)
        end

おわりに

サービスが大きくなるとroutesが肥大化してきて辛くなってくると思うのですが、標準機能でこの辺に楽に対応できるのは良いですね✨

参考

tech.toreta.in