Alexander Bird
Alexander Bird

Reputation: 40678

where exactly is the rails "root" function defined?

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

Answers (2)

Jeff Peterson
Jeff Peterson

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

Leszek Andrukanis
Leszek Andrukanis

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

Related Questions