module ActiveSupport::Concern
A typical module looks like this:
module M def self.included(base) base.extend ClassMethods base.class_eval do scope :disabled, -> { where(disabled: true) } end end module ClassMethods ... end end
By using ActiveSupport::Concern
the above module could instead be written as:
require 'active_support/concern' module M extend ActiveSupport::Concern included do scope :disabled, -> { where(disabled: true) } end class_methods do ... end end
Moreover, it gracefully handles module dependencies. Given a Foo
module and a Bar
module which depends on the former, we would typically write the following:
module Foo def self.included(base) base.class_eval do def self.method_injected_by_foo ... end end end end module Bar def self.included(base) base.method_injected_by_foo end end class Host include Foo # We need to include this dependency for Bar include Bar # Bar is the module that Host really needs end
But why should Host
care about Bar
's dependencies, namely Foo
? We could try to hide these from Host
directly including Foo
in Bar
:
module Bar include Foo def self.included(base) base.method_injected_by_foo end end class Host include Bar end
Unfortunately this won't work, since when Foo
is included, its base
is the Bar
module, not the Host
class. With ActiveSupport::Concern
, module dependencies are properly resolved:
require 'active_support/concern' module Foo extend ActiveSupport::Concern included do def self.method_injected_by_foo ... end end end module Bar extend ActiveSupport::Concern include Foo included do self.method_injected_by_foo end end class Host include Bar # It works, now Bar takes care of its dependencies end
Public Instance Methods
# File activesupport/lib/active_support/concern.rb, line 111 def append_features(base) if base.instance_variable_defined?(:@_dependencies) base.instance_variable_get(:@_dependencies) << self return false else return false if base < self @_dependencies.each { |dep| base.send(:include, dep) } super base.extend const_get(:ClassMethods) if const_defined?(:ClassMethods) base.class_eval(&@_included_block) if instance_variable_defined?(:@_included_block) end end
Calls superclass method
# File activesupport/lib/active_support/concern.rb, line 134 def class_methods(&class_methods_module_definition) mod = const_defined?(:ClassMethods, false) ? const_get(:ClassMethods) : const_set(:ClassMethods, Module.new) mod.module_eval(&class_methods_module_definition) end
# File activesupport/lib/active_support/concern.rb, line 124 def included(base = nil, &block) if base.nil? raise MultipleIncludedBlocks if instance_variable_defined?(:@_included_block) @_included_block = block else super end end
Calls superclass method
© 2004–2018 David Heinemeier Hansson
Licensed under the MIT License.