有时想在controller中调用一些view的helper,如raw、j、t之类,可通过view_context来调

看看这个方法来自哪里

[1] pry(main)> ctrl = StudentsController.new
=> #<studentscontroller:0x007f5bfc4a5240 @_action_has_layout="true," @_request="nil," @_response="nil," @_routes="nil">
[2] pry(main)> binding.trace_tree(htmp: 'view_context/vc'){ ctrl.view_context }
=> #<#:0x007f5bfae45bf8
@_assigns={},
@_config={},
@_controller=
  #<studentscontroller:0x007f5bfc4a5240   #="" ...<="" code=""></studentscontroller:0x007f5bfc4a5240></studentscontroller:0x007f5bfc4a5240>


调用栈如下

20171005_105106_807_vc.html

想知道view_context上有什么方法可用,当然可以直接view_context.methods.sort打印出来,但为了有个系统一点概念,还是看看源码它是怎样定义这些方法的。简单来说,这些方法是分布在actionpack、actionview的各个功能module中的,然后通过继承和mixin而加进来,脉络如下


源码如下

module ActionView
  module Rendering

    module ClassMethods
      def view_context_class
        @view_context_class ||= begin
          supports_path = supports_path?
          routes  = respond_to?(:_routes)  && _routes
          helpers = respond_to?(:_helpers) && _helpers

          Class.new(ActionView::Base) do
            if routes
              include routes.url_helpers(supports_path)
              include routes.mounted_helpers
            end

            if helpers
              include helpers
            end
          end
        end
      end
    end

    attr_internal_writer :view_context_class

    def view_context_class
      @_view_context_class ||= self.class.view_context_class
    end

    def view_context
      view_context_class.new(view_renderer, view_assigns, self)
    end


不过一般来说,像url_helpers这些其实controller中本来就有了(mixin到了controller的ancestors的匿名module中),在controller中使用view_context主要还是为了获得ActionView::Base所mixin的那些页面helper(如果真的有必要在controller里干view的活……)