はじめに
Rails Engineは複数のプロジェクトで、同じアプリケーションの機能を提供したい場合に使いますよね
有名なgemではdeviceとかでしょうか
そんなRails Engineですが、上位アプリケーションで独自の機能を追加したいときがあります
今回はRoutesにフォーカスします
上位アプリケーションで、Rails EngineのRoutesを上書き、追加してみましょう
Rails Routes
アプリケーションのルーティングを定義します
Rails.application.routes.draw do
resources :posts
end
Rails Engineではこんな感じです
MyEngine::Engine.routes.draw do
resources :users
end
draw
このdraw
メソッドが何をやっているのか見てみる
def draw(&block)
clear! unless @disable_clear_and_finalize
eval_block(block)
finalize! unless @disable_clear_and_finalize
nil
end
なんかclear!して、blockを展開して、finalize!している
clear!
clear!が何をしているのか見てみる
def clear!
@finalized = false
named_routes.clear
set.clear
formatter.clear
@polymorphic_mappings.clear
@prepend.each { |blk| eval_block(blk) }
end
なんか@prepend
を展開してますね
@prepend
はどこでセットされてるのか?
def prepend(&block)
@prepend << block
end
prependってメソッドのblockが展開されることがわかります
ってことは、prependで定義されたroutesは、アプリケーションのdrawで定義された手前に差し込まれるってことです
Railsのroutesは上から順番にマッチングされるので、定義済みのルーティングを上書きしたりできます
finalize!
finalize!が何をしているのかを見てみる
def finalize!
return if @finalized
@append.each { |blk| eval_block(blk) }
@finalized = true
end
@append
を展開してますね
@append
はどこでセットされているのか?
def append(&block)
@append << block
end
appendってメソッドのblockが展開されていることがわかります
ってことは、appendで定義されたroutesは、アプリケーションのdrawで定義されたあとに差し込まれるってことです
なので、単純にRoutesを追加することができますが、アプリケーションで定義されているルーティングが優先されます
Rails EngineのRoutesを上書き
では、Engineのroutesを上書きしてみる
こんなルーティングが定義されていて、ネストしたルーティングに上書きしたい!
MyEngine::Engine.routes.draw do
resources :users
end
上書きなので、prepend
を使って定義します
こういうネストをさせたいユースケースは、Engineの名前空間を利用したいときですかね
MyEngine::Engine.routes.prepend do
resources :users do
resources: posts
end
end
追加したい場合は、append
を使って定義します
MyEngine::Engine.routes.append do
resources: posts
end
まとめ
今回はRilas EngineのRoutesを上書き、追加する方法を、Railsのコードをみながら書きました
もちろん、上位アプリでも同じことができます
prepend
,append
を使って、肥大化したroutesのファイルを分割したりもできますね