Module: ActiveSupport::Concern
- Included in:
 - ActionableError, Callbacks, Configurable, LoggerSilence, LoggerThreadSafeLevel, Rescuable, Testing::ConstantLookup, Testing::FileFixtures
 
- Defined in:
 - lib/active_support/concern.rb
 
Overview
Active Support 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
Prepending concerns
Just like include, concerns also support prepend with a corresponding prepended do callback. module ClassMethods or class_methods do are prepended as well.
prepend is also used for any dependencies.
Defined Under Namespace
Classes: MultipleIncludedBlocks, MultiplePrependBlocks
Class Method Summary collapse
- 
  
    
      .extended(base)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
:nodoc:.
 
Instance Method Summary collapse
- 
  
    
      #append_features(base)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
:nodoc:.
 - 
  
    
      #class_methods(&class_methods_module_definition)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
Define class methods from given block.
 - 
  
    
      #included(base = nil, &block)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
Evaluate given block in context of base class, so that you can write class macros here.
 - 
  
    
      #prepend_features(base)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
:nodoc:.
 - 
  
    
      #prepended(base = nil, &block)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
Evaluate given block in context of base class, so that you can write class macros here.
 
Class Method Details
.extended(base) ⇒ Object
:nodoc:
      125 126 127  | 
    
      # File 'lib/active_support/concern.rb', line 125 def self.extended(base) # :nodoc: base.instance_variable_set(:@_dependencies, []) end  | 
  
Instance Method Details
#append_features(base) ⇒ Object
:nodoc:
      129 130 131 132 133 134 135 136 137 138 139 140  | 
    
      # File 'lib/active_support/concern.rb', line 129 def append_features(base) # :nodoc: if base.instance_variable_defined?(:@_dependencies) base.instance_variable_get(:@_dependencies) << self false else return false if base < self @_dependencies.each { |dep| base.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) ⇒ Object
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 ; puts 'bar'; end
  end
end
class Buzz
  include Example
end
Buzz.foo # => "foo"
Buzz. # => private method 'bar' called for Buzz:Class(NoMethodError)
  
      209 210 211 212 213 214 215  | 
    
      # File 'lib/active_support/concern.rb', line 209 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) ⇒ Object
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.
      158 159 160 161 162 163 164 165 166 167 168 169 170  | 
    
      # File 'lib/active_support/concern.rb', line 158 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  | 
  
#prepend_features(base) ⇒ Object
:nodoc:
      142 143 144 145 146 147 148 149 150 151 152 153  | 
    
      # File 'lib/active_support/concern.rb', line 142 def prepend_features(base) # :nodoc: if base.instance_variable_defined?(:@_dependencies) base.instance_variable_get(:@_dependencies).unshift self false else return false if base < self @_dependencies.each { |dep| base.prepend(dep) } super base.singleton_class.prepend const_get(:ClassMethods) if const_defined?(:ClassMethods) base.class_eval(&@_prepended_block) if instance_variable_defined?(:@_prepended_block) end end  | 
  
#prepended(base = nil, &block) ⇒ Object
Evaluate given block in context of base class, so that you can write class macros here. When you define more than one prepended block, it raises an exception.
      175 176 177 178 179 180 181 182 183 184 185 186 187  | 
    
      # File 'lib/active_support/concern.rb', line 175 def prepended(base = nil, &block) if base.nil? if instance_variable_defined?(:@_prepended_block) if @_prepended_block.source_location != block.source_location raise MultiplePrependBlocks end else @_prepended_block = block end else super end end  |