Rails Engine is used when you want to provide the functionality of the same application in multiple projects, right?
Is it device in the famous gem?
Although it is such a Rails Engine, there are times when you want to add unique functions in a higher-level application.
This time we will focus on Routes
Let's overwrite and add Rails Engine Routes in the upper application
Rails Routes Defines the routing of the application
routes.rb
Rails.application.routes.draw do
resources :posts
end
Rails Engine looks like this
routes.rb
MyEngine::Engine.routes.draw do
resources :users
end
draw
Let's see what this draw
method is doing
https://github.com/rails/rails/blob/66a4cf4bbc0651b995646ad86aa76f5634da49c5/actionpack/lib/action_dispatch/routing/route_set.rb#L407-L412
rails/actionpack/lib/action_dispatch/routing/route_set.rb
def draw(&block)
clear! unless @disable_clear_and_finalize
eval_block(block)
finalize! unless @disable_clear_and_finalize
nil
end
Something is cleared !, block is expanded, and finalize!
clear! See what clear! is doing
https://github.com/rails/rails/blob/66a4cf4bbc0651b995646ad86aa76f5634da49c5/actionpack/lib/action_dispatch/routing/route_set.rb#L438-L445
rails/actionpack/lib/action_dispatch/routing/route_set.rb
def clear!
@finalized = false
named_routes.clear
set.clear
formatter.clear
@polymorphic_mappings.clear
@prepend.each { |blk| eval_block(blk) }
end
Somehow you are expanding @prepend
Where is @prepend
set?
rails/actionpack/lib/action_dispatch/routing/route_set.rb
def prepend(&block)
@prepend << block
end
You can see that the block of the method is expanded by prepend
This means that the routes defined in prepend will be plugged in front of the one defined in the application's draw.
Rails routes are matched from top to bottom, allowing you to override predefined routes.
finalize! Let's see what finalize! Is doing
https://github.com/rails/rails/blob/66a4cf4bbc0651b995646ad86aa76f5634da49c5/actionpack/lib/action_dispatch/routing/route_set.rb#L432-L436
rails/actionpack/lib/action_dispatch/routing/route_set.rb
def finalize!
return if @finalized
@append.each { |blk| eval_block(blk) }
@finalized = true
end
You are expanding @append
Where is @append
set?
rails/actionpack/lib/action_dispatch/routing/route_set.rb
def append(&block)
@append << block
end
You can see that the block of the method called append is expanded
This means that the routes defined in append will be plugged in after being defined in the application's draw.
So you can simply add Routes, but the routing defined in your application will take precedence.
Let's overwrite the Engine routes
Such a routing is defined and I want to overwrite the nested routing!
routes.rb
MyEngine::Engine.routes.draw do
resources :users
end
Since it is an overwrite, it is defined using prepend
The use case where you want to nest like this is when you want to use the engine namespace.
config/initializers/my_engine_routes.rb
MyEngine::Engine.routes.prepend do
resources :users do
resources: posts
end
end
If you want to add it, define it using append
config/initializers/my_engine_routes.rb
MyEngine::Engine.routes.append do
resources: posts
end
This time, I wrote how to overwrite and add Routes of Rilas Engine while looking at the Rails code.
Of course, you can do the same with higher-level apps
You can also use prepend
, append
to split the bloated routes file.
Recommended Posts