How helper_method brings methods to view level

In Rails we can do things like

 
class ApplicationController < ActionController::Base
  helper_method :current_user, :logged_in?

  def current_user
    @current_user ||= User.find_by_id(session[:user])
  end

   def logged_in?
     current_user != nil
   end
end

And now the methods current_user and logged_in? can be used anywhere in the view. This is good.

Question is how does Rails implement this behavior?

In actionpack gem at lib/action_controller/helpers.rb we have following code:

 
def self.included(base)
   base.class_inheritable_accessor :master_helper_module
   base.master_helper_module = Module.new
end

As we saw above master_helper_module is a Module and it is this module in which helper methods would be defined. Given below is the definition of the method helper_method

 
def helper_method(*methods)
  methods.flatten.each do |method|
    master_helper_module.module_eval <<-end_eval
      def #{method}(*args, &block)
        controller.send(%(#{method}), *args, &block)
      end
    end_eval
  end
end

Now we have the master_helper_module with the helper_method. All we need to do it to attach this module to ActionView somehow. And that is done here.

 
# lib/action_controller/base.rb
def initialize_template_class(response)
  response.template = ActionView::Base.new(self.class.view_paths, {}, self)
  response.template.extend self.class.master_helper_module
  response.redirected_to = nil
  @performed_render = @performed_redirect = false
end

In the above code when the template is being initialized then an instance of ActionView:Base is create. And then that template extends the master_helper_module.

And that is how the helper_method defined in controller gets to the template. Now in the view if call current_person then view understands that method because that method has been added to the template.

Fascinating!

My name is Neeraj. You can contact me at neerajdotname@gmail.com . I am also on twitter , facebook and Linkedin .

Checkout my github account for admin_data and other projects.