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
append_features(base)
click to toggle source
Calls superclass method
# File 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
class_methods(&class_methods_module_definition)
click to toggle source
# File 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
included(base = nil, &block)
click to toggle source
Calls superclass method
# File 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