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?