How to "nest" the inclusion of modules when using the Ruby on Rails ActiveSupport::Concern feature?

include, module, nested, ruby, ruby-on-rails

Solution

If you include `MyModuleB` in the "body" of `MyModuleA`, then it is the module itself that is extended with B's functionality. If you include it in the `included` block, then it is included on the class that mixes in `MyModuleA`.

That is:

module MyModuleA
  extend ActiveSupport::Concern
  include MyModuleB
end

produces something like:

MyModuleA.send :include, MyModuleB
class Foo
  include MyModuleA
end

while

module MyModuleA
  extend ActiveSupport::Concern
  included do
    include MyModuleB
  end
end

produces something like:

class Foo
  include MyModuleA
  include MyModuleB
end

The reason for this is that `ActiveSupport::Concern::included` is analogous to:

def MyModuleA
  def self.included(klass, &block)
    klass.instance_eval(&block)
  end
end

The code in the `included` block is run in the context of the including class, rather than the context of the module. Thus, if MyModuleB needs access to the class it's being mixed-in to, then you'd want to run it in the `included` block. Otherwise, it's effectively the same thing.

By means of demonstration:

module A
  def self.included(other)
    other.send :include, B
  end
end

module B
  def self.included(other)
    puts "B was included on #{other.inspect}"
  end
end

module C
  include B
end

class Foo
  include A
end

# Output:
# B was included on C
# B was included on Foo

Problem

I am using Ruby 1.9.2 and the Ruby on Rails v3.2.2 gem. I would like to "nest" the inclusion of modules given I am using the RoR ActiveSupport::Concern feature, but I have a doubt where I should state the `include` method. That is, I have the following: ``` module MyModuleA extend ActiveSupport::Concern # include MyModuleB included do # include MyModuleB end end ``` Should I state `include MyModuleB` in the "body" / "context" / "scope" of `MyModuleA` or I should state that in the `included do ... end` block? What is the difference and what I should expect from that?

Original source