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 163 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
Define class methods from given block. You can define private class methods as well.
module Example extend ActiveSupport::Concern class_methods do def foo; puts 'foo'; end private def bar; puts 'bar'; end end end class Buzz include Example end Buzz.foo # => "foo" Buzz.bar # => private method 'bar' called for Buzz:Class(NoMethodError)
# File activesupport/lib/active_support/concern.rb, line 129 def included(base = nil, &block) if base.nil? if instance_variable_defined?(:@_included_block) if @_included_block.source_location != block.source_location raise MultipleIncludedBlocks end else @_included_block = block end else super end end
Evaluate given block in context of base class, so that you can write class macros here. When you define more than one included
block, it raises an exception.
© 2004–2019 David Heinemeier Hansson
Licensed under the MIT License.