2

一篇关于ActiveSupport::Concern钩子的文章。这是 Rails 中的一个有效实现:

module ActionController
  class Base < Metal
    include AbstractController::Layouts
  end
end

module AbstractController
  module Layouts
    extend ActiveSupport::Concern

    include Rendering

    included do
      class_attribute :_layout, :_layout_conditions, :instance_accessor => false
      self._layout = nil
      self._layout_conditions = {}
      _write_layout_method
    end

    module ClassMethods
      ...
    end
  end
end

module AbstractController
  module Rendering
    extend ActiveSupport::Concern

    included do
      class_attribute :protected_instance_variables
      self.protected_instance_variables = []
    end

    module ClassMethods
      ...
    end
  end
end

在ruby​​ 钩子之前如何执行extend调用?必须先执行。毕竟,它的全部意义在于劫持ruby​​ 默认并重新实现它。但是,根据 Ruby 文档,在您将此模块(例如)包含在另一个(例如)中之后立即执行。所以这里对我来说很困惑。如果是这种情况,则永远不会调用覆盖的。Layoutsappend_featuresextendappend_featuresappend_featuresAbstractController::LayoutsActionController::Baseappend_featuresActiveSupport::Concern

4

1 回答 1

1

这是我的看法:

您可以将“包含”视为将模块作为参数的方法;为了包含一个模块,该模块必须已经被环境加载;否则,该行将因缺少常量错误而失败。

因此,当include AbstractController::Layouts被调用时,必须将 Layouts 加载到 AbstractController 或顶级命名空间中才能正常工作。

查看 actionpack 源代码,发现 Layouts是 autoloaded,这确保了它会在“include”行完成之前被加载。

由于在加载extend ActiveSupport::ConcernLayouts 时执行,因此在 ActionController::Base 中的“include”行完成执行时,覆盖将可用append_features

之后,Layouts 的 append_features 方法将使用 ActionController::Base 作为参数执行。

于 2012-09-24T13:29:35.373 回答