1 如何使用
默认情况下MyController自动包含MyHelper,
add_template_helper 方法可以用来添加自定义的helper Module
如果想另外添加,可以用
helper 方法来指定:
- # ==== Examples
- # The +to_s+ method from the Time class can be wrapped in a helper method to display a custom message if
- # the Time object is blank:
- #
- module FormattedTimeHelper
- def format_time(time, format=:long, blank_message=" ")
- time.blank? ? blank_message : time.to_s(format)
- end
- end
- #
- # FormattedTimeHelper can now be included in a controller, using the +helper+ class method:
- #
- class EventsController < ActionController::Base
- helper FormattedTimeHelper
- def index
- @events = Event.find(:all)
- end
- end
- #
- # Then, in any view rendered by <tt>EventController</tt>, the <tt>format_time</tt> method can be called:
- #
- <% @events.each do |event| -%>
- <p>
- <% format_time(event.time, :short, "N/A") %> | <%= event.name %>
- </p>
- <% end -%>
- # * <tt>*args</tt>: One or more modules, strings or symbols, or the special symbol <tt>:all</tt>.
- # * <tt>&block</tt>: A block defining helper methods.
- #
- # ==== Examples
- # When the argument is a string or symbol, the method will provide the "_helper" suffix, require the file
- # and include the module in the template class. The second form illustrates how to include custom helpers
- # when working with namespaced controllers, or other cases where the file containing the helper definition is not
- # in one of Rails' standard load paths:
- helper :foo # => requires 'foo_helper' and includes FooHelper
- helper 'resources/foo' # => requires 'resources/foo_helper' and includes Resources::FooHelper
- #
- # When the argument is a module it will be included directly in the template class.
- # helper FooHelper # => includes FooHelper
- #
- # When the argument is the symbol <tt>:all</tt>, the controller will include all helpers from
- # <tt>app/helpers/**/*.rb</tt> under RAILS_ROOT.
- helper :all
- #
- # Additionally, the +helper+ class method can receive and evaluate a block, making the methods defined available
- # to the template.
- # # One line
- helper { def hello() "Hello, world!" end }
- # # Multi-line
- helper do
- def foo(bar)
- "#{bar} is the very best"
- end
- end
- # Finally, all the above styles can be mixed together, and the +helper+ method can be invoked with a mix of
- # +symbols+, +strings+, +modules+ and blocks.
- helper(:three, BlindHelper) { def mice() 'mice' end }
- # Declare a controller method as a helper. For example, the following
- # makes the +current_user+ controller method available to the view:
- 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
- #
- # In a view:
- <% if logged_in? -%>Welcome, <%= current_user.name %><% end -%>
主要是为了在view中调用controller中的attributes,比如:
# helper_attr :name
# attr_accessor :name
helpers 类方法的使用
在view以外的地方调用helper方法的一个代理
2 实现
先看看入口:
- def self.included(base)
- # 初始化一个module容器来包含这个controller所有的helpers module
- # 这个是整个helper和controller结合最关键的部分
- base.class_inheritable_accessor :master_helper_module
- base.master_helper_module = Module.new
- # Extend base with class methods to declare helpers.
- base.extend(ClassMethods)
- base.class_eval do
- # Wrap inherited to create a new master helper module for subclasses.
- class << self
- alias_method_chain :inherited, :helper
- end
- end
- end
1 base.extend(ClassMethod),增加了几个类方法,就是上面提到的几个
2 动态修改了一个类方法:
alias_method_chain :inherited, :helper
所以controller继承父类后的调用包含helper的功能在 inherited_with_helper 里
- def inherited_with_helper(child)
- inherited_without_helper(child)
- begin
- # 增加helper module到child controller中的helper容器中
- child.master_helper_module = Module.new
- child.master_helper_module.send! :include, master_helper_module
- child.send! :default_helper_module!
- rescue MissingSourceFile => e
- raise unless e.is_missing?("helpers/#{child.controller_path}_helper")
- end
- end
- # 设置默认的helper module
- def default_helper_module!
- unless name.blank?
- # 取得module默认的名字,根据名字获取路径,将其加入到helper 中
- module_name = name.sub(/Controller$|$/, 'Helper')
- module_path = module_name.split('::').map { |m| m.underscore }.join('/')
- require_dependency module_path
- helper module_name.constantize
- end
- rescue MissingSourceFile => e
- raise unless e.is_missing? module_path
- rescue NameError => e
- raise unless e.missing_name? module_name
- end
- def helper(*args, &block)
- args.flatten.each do |arg|
- case arg
- # 如果是Module则调用add_template_helper直接添加
- when Module
- add_template_helper(arg)
- # 如果是:all 则包含所有的applicatioin_helpers
- when :all
- helper(all_application_helpers)
- # 如果是string或者symbol,那么根据名字来获取helper名字,加载后用add_template_helper添加
- when String, Symbol
- file_name = arg.to_s.underscore + '_helper'
- class_name = file_name.camelize
- begin
- require_dependency(file_name)
- rescue LoadError => load_error
- requiree = / -- (.*?)(/.rb)?$/.match(load_error.message).to_a[1]
- if requiree == file_name
- msg = "Missing helper file helpers/#{file_name}.rb"
- raise LoadError.new(msg).copy_blame!(load_error)
- else
- raise
- end
- end
- add_template_helper(class_name.constantize)
- else
- raise ArgumentError, "helper expects String, Symbol, or Module argument (was: #{args.inspect})"
- end
- end
- # 传入block的就直接定义在helper module容器中
- master_helper_module.module_eval(&block) if block_given?
- end
- # 这个方法主要动态include module到helper容器
- def add_template_helper(helper_module) #:nodoc:
- master_helper_module.module_eval { include helper_module }
- end
- # 这个方法动态的定义方法到helper容器中
- 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
- # 调用helper_methods增加attr和attr=方法到helper容器中
- def helper_attr(*attrs)
- attrs.flatten.each { |attr| helper_method(attr, "#{attr}=") }
- end
明天继续