Reputation: 40678
I see something like the following in a rails applications:
Application.routes.draw do
root :to => "accounts#index"
end
I'm told here that this will define where rails routes to if "/" is the path asked for. However, where the heck is this 'root' function defined in rails code? I don't understand what scoping issues are involved to get this trick to work.
I can see that a block is being passed to the draw
function. So I'm assuming that the draw
function calls yield
to execute the passed block. But I'm still not sure why the root
function will magically be inside the scope of the passed block.
Upvotes: 2
Views: 490
Reputation: 1459
root
is defined on ActionDispatch::Routing::Mapper::Base
, which is included by ActionDispatch::Routing::Mapper
.
There is a little more going on behind the scenes than at first glance.
If we look at the definition of draw
, we can see why:
# action_dispatch/routing/route_set.rb
def draw(&block)
# ...
eval_block(block)
# ...
end
The block is converted to a proc (with &
) and passed to eval_block
which is defined a bit farther down:
def eval_block(block)
# ...
mapper = Mapper.new(self)
# ...
mapper.instance_exec(&block)
end
So, as it turns out, yield
isn't used at all. The block we pass to Application.routes.draw
is just being evaluated in the context of an instance of ActionDispatch::Routing::Mapper
.
If we add puts self
to our config/routes.rb
, we can see this in action:
Application.routes.draw do
puts self
end
When we run rake routes
we get something similar to the following:
#<ActionDispatch::Routing::Mapper:0x007feadf52cbd8>
# ...
For further reading, see:
http://ruby-doc.org/core-1.8.7/Object.html#method-i-instance_exec https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/routing/route_set.rb#LC296 https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/routing/mapper.rb#LC336 http://www.amazon.com/Metaprogramming-Ruby-Program-Like-Pros/dp/1934356476
Upvotes: 5
Reputation: 2125
https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/routing/mapper.rb
def root(options = {})
options = { :to => options } if options.is_a?(String)
match '/', { :as => :root, :via => :get }.merge!(options)
end
https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/routing.rb
module Routing
autoload :Mapper, 'action_dispatch/routing/mapper'
Upvotes: 1