I read this post: Ruby modules - included do end block – but still don't get when you would use the self.included do ... end
block in a module.
The post says that code in the block will be ran when you include the module, but what's the point of that if a module's sole purpose is to be included? Wouldn't that code need to be run anyway? That block doesn't need to be there in order for that code to be run, right?
What would be the difference between the two below:
module M
def self.included(base)
base.extend ClassMethods
base.class_eval do
scope :disabled, -> { where(disabled: true) }
end
end
module ClassMethods
...
end
end
vs.
module M
def self.some_class_method
...
end
scope :disabled, -> { where(disabled: true) }
end
module M
# self.included is the hook which automatically runs when this module is included
def self.included(base)
puts 'this will be printed when this module will be included inside a class'
base.extend ClassMethods
base.class_eval do
scope :disabled, -> { where(disabled: true) }
end
end
def print_object_class
self.class.name # here self will be the object of class which includes this module
end
module ClassMethods
def print_class_name
self.name # Here self would be the class which is including this module
end
end
end
I tried to modify the above module
to help you understand how a module(concern) can be helpful in code reusability
self.included
is a hook which runs automatically when a module is included inside a class.
any method declare in the module ClassMethods
will become class methods for the class including this module
any method declare outside the module ClassMethods
will become instance methods for the class including this module
For Ex suppose there is a class Product and you have included the module in it
class Product < ActiveRecord::Base
include M
puts 'after including M'
end
If you try this example in you rails console you will notice that as soon as the module M
gets included in class Product
included hook of module run and
this will be printed when this module will be included inside a class
this is printed on console
after that after including M
this will be printed on the console.
Also you can try following commands
Product.disabled # a scope with name 'disabled' is avaialble because of including the module M
Product.print_class_name # Outputs => 'Product' This method is available to class with the help of module M
Product.new.print_object_class #Outputs => 'Product'
It also offers reusability, include this module M in any class and that class gets access to all those methods described in the module.
Whereas your second example is a mere example of basic module
module N
def self.abc
puts 'basic module'
end
end
Now abc
method define in module can be accessible using only this module
N.abc # outputs 'basic module'
class Product < ActiveRecord::Base
include N
end
Product.abc #raises exception, No method found on class Product Product.new.abc #raises exception, No method found on object of class Product
I hope this may help you understand the concept of module better. Please let me know if you still have any doubts.
The first code block adds the class methods in ClassMethods
to the including class and calls the scope
method on it as well. The second one does neither of these things and will result in a NoMethodError
because the module has no scope
class method. self.some_class_method
will not be available on the including class once the module is included.
For the full story on how module inclusion works in Ruby, read my answer here:
Inheriting class methods from modules / mixins in Ruby
self.included
if a module's sole purpose is to be included?Inclusion is not the only purpose of modules. They are also used for other things such as namespacing or simply storing various class methods that are then callable on the module itself.
Theoretically Ruby could automatically add all class methods defined in a module to the including class, but in practice that would be a bad idea, because you would not get to choose anymore whether you want to include class methods — all class methods would be included every time, whether or not they are intended to be included. Consider this example:
module M
def self.class_method
"foo"
end
def self.configure_module
# add configuration for this module
end
end
class C
include M
end
Here, the configure_module
method is obviously not supposed to be added to C
, as its purpose is to set the configuration for the module object. Yet, if we had auto-inclusion for class methods, you would not be able to prevent it from being included.
But all instance methods are already included! How is that okay then?
Instance methods in a module are only really useful if they are included into a class, since modules cannot have instances, only classes can. So in a module every instance method is expected to be included somewhere to work.
A "class" method on a module is different, because it can be called on the module itself, so it can be used just fine regardless of whether it's also added to the including class. That is why it is better that you have a choice there.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With