1 如何使用

默认情况下MyController自动包含MyHelper,

add_template_helper 方法可以用来添加自定义的helper Module

如果想另外添加,可以用 helper 方法来指定:
  1.     # ==== Examples
  2.     # The +to_s+ method from the Time class can be wrapped in a helper method to display a custom message if 
  3.     # the Time object is blank:
  4.     #
  5.        module FormattedTimeHelper
  6.          def format_time(time, format=:long, blank_message=" ")
  7.            time.blank? ? blank_message : time.to_s(format)
  8.          end
  9.        end
  10.     #
  11.     # FormattedTimeHelper can now be included in a controller, using the +helper+ class method:
  12.     #
  13.        class EventsController < ActionController::Base
  14.          helper FormattedTimeHelper
  15.          def index
  16.            @events = Event.find(:all)
  17.          end
  18.        end
  19.     #
  20.     # Then, in any view rendered by <tt>EventController</tt>, the <tt>format_time</tt> method can be called:
  21.     #
  22.        <% @events.each do |event| -%>
  23.          <p>
  24.            <% format_time(event.time, :short"N/A") %> | <%= event.name %> 
  25.          </p>
  26.        <% end -%>
helper这个类方法的详细使用有如下几种方式:
  1.       # * <tt>*args</tt>: One or more modules, strings or symbols, or the special symbol <tt>:all</tt>.
  2.       # * <tt>&block</tt>: A block defining helper methods.
  3.       
  4.       # ==== Examples
  5.       # When the argument is a string or symbol, the method will provide the "_helper" suffix, require the file 
  6.       # and include the module in the template class.  The second form illustrates how to include custom helpers 
  7.       # when working with namespaced controllers, or other cases where the file containing the helper definition is not
  8.       # in one of Rails' standard load paths:
  9.          helper :foo             # => requires 'foo_helper' and includes FooHelper
  10.          helper 'resources/foo'  # => requires 'resources/foo_helper' and includes Resources::FooHelper
  11.       #
  12.       # When the argument is a module it will be included directly in the template class.
  13.       #   helper FooHelper # => includes FooHelper
  14.       #
  15.       # When the argument is the symbol <tt>:all</tt>, the controller will include all helpers from 
  16.       # <tt>app/helpers/**/*.rb</tt> under RAILS_ROOT.
  17.          helper :all
  18.       #
  19.       # Additionally, the +helper+ class method can receive and evaluate a block, making the methods defined available 
  20.       # to the template.
  21.       #   # One line
  22.          helper { def hello() "Hello, world!" end }
  23.       #   # Multi-line
  24.          helper do
  25.            def foo(bar) 
  26.              "#{bar} is the very best" 
  27.            end
  28.          end
  29.        
  30.       # Finally, all the above styles can be mixed together, and the +helper+ method can be invoked with a mix of
  31.       # +symbols+, +strings+, +modules+ and blocks.
  32.          helper(:three, BlindHelper) { def mice() 'mice' end }
helper_method方法可以把controller方法定义为helper方法
  1.       # Declare a controller method as a helper. For example, the following
  2.       # makes the +current_user+ controller method available to the view:
  3.          class ApplicationController < ActionController::Base
  4.            helper_method :current_user:logged_in?
  5.       
  6.            def current_user
  7.              @current_user ||= User.find_by_id(session[:user])
  8.            end
  9.       
  10.             def logged_in?
  11.               current_user != nil
  12.             end
  13.          end
  14.       #
  15.       # In a view:
  16.         <% if logged_in? -%>Welcome, <%= current_user.name %><% end -%>
helper_attr 类方法的使用

主要是为了在view中调用controller中的attributes,比如:
      #   helper_attr :name
      #   attr_accessor :name

helpers 类方法的使用

在view以外的地方调用helper方法的一个代理

2 实现
先看看入口:
  1.     def self.included(base)
  2.       # 初始化一个module容器来包含这个controller所有的helpers module
  3.       # 这个是整个helper和controller结合最关键的部分
  4.       base.class_inheritable_accessor :master_helper_module
  5.       base.master_helper_module = Module.new
  6.       # Extend base with class methods to declare helpers.
  7.       base.extend(ClassMethods)
  8.       base.class_eval do
  9.         # Wrap inherited to create a new master helper module for subclasses.
  10.         class << self
  11.           alias_method_chain :inherited:helper
  12.         end
  13.       end
  14.     end
可以看到
1 base.extend(ClassMethod),增加了几个类方法,就是上面提到的几个
2  动态修改了一个类方法:  alias_method_chain :inherited:helper

所以controller继承父类后的调用包含helper的功能在  inherited_with_helper 里
  1.         def inherited_with_helper(child)
  2.           inherited_without_helper(child)
  3.           begin
  4.           # 增加helper module到child controller中的helper容器中
  5.             child.master_helper_module = Module.new
  6.             child.master_helper_module.send! :include, master_helper_module
  7.             child.send! :default_helper_module!
  8.           rescue MissingSourceFile => e
  9.             raise unless e.is_missing?("helpers/#{child.controller_path}_helper")
  10.           end
  11.         end
  1.         # 设置默认的helper module
  2.         def default_helper_module!
  3.           unless name.blank?
  4.             # 取得module默认的名字,根据名字获取路径,将其加入到helper 中
  5.             module_name = name.sub(/Controller$|$/, 'Helper')
  6.             module_path = module_name.split('::').map { |m| m.underscore }.join('/')
  7.             require_dependency module_path
  8.             helper module_name.constantize
  9.           end
  10.         rescue MissingSourceFile => e
  11.           raise unless e.is_missing? module_path
  12.         rescue NameError => e
  13.           raise unless e.missing_name? module_name
  14.         end
我们调用的主要方法  helper 如下
  1.       def helper(*args, &block)
  2.         args.flatten.each do |arg|
  3.           case arg
  4.             # 如果是Module则调用add_template_helper直接添加
  5.             when Module
  6.               add_template_helper(arg)
  7.             # 如果是:all 则包含所有的applicatioin_helpers
  8.             when :all
  9.               helper(all_application_helpers)
  10.             # 如果是string或者symbol,那么根据名字来获取helper名字,加载后用add_template_helper添加
  11.             when StringSymbol
  12.               file_name  = arg.to_s.underscore + '_helper'
  13.               class_name = file_name.camelize
  14.               begin
  15.                 require_dependency(file_name)
  16.               rescue LoadError => load_error
  17.                 requiree = / -- (.*?)(/.rb)?$/.match(load_error.message).to_a[1]
  18.                 if requiree == file_name
  19.                   msg = "Missing helper file helpers/#{file_name}.rb"
  20.                   raise LoadError.new(msg).copy_blame!(load_error)
  21.                 else
  22.                   raise
  23.                 end
  24.               end
  25.               add_template_helper(class_name.constantize)
  26.             else
  27.               raise ArgumentError, "helper expects String, Symbol, or Module argument (was: #{args.inspect})"
  28.           end
  29.         end
  30.         # 传入block的就直接定义在helper module容器中
  31.         master_helper_module.module_eval(&block) if block_given?
  32.       end
  1.       # 这个方法主要动态include module到helper容器
  2.       def add_template_helper(helper_module) #:nodoc:
  3.         master_helper_module.module_eval { include helper_module }
  4.       end
  1.       # 这个方法动态的定义方法到helper容器中
  2.      def helper_method(*methods)
  3.         methods.flatten.each do |method|
  4.           master_helper_module.module_eval <<-end_eval
  5.             def #{method}(*args, &block)
  6.               controller.send(%(#{method}), *args, &block)
  7.             end
  8.           end_eval
  9.         end
  10.       end
  1.       # 调用helper_methods增加attr和attr=方法到helper容器中
  2.       def helper_attr(*attrs)
  3.         attrs.flatten.each { |attr| helper_method(attr, "#{attr}=") }
  4.       end
总的来说helper模块比较容易看懂~
明天继续

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐