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!