Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does class_methods do in concerns?

Tags:

I am reading some codes which use the concerns in Rails 4.

I read some articles to say, if we would like to include class methods using module ClassMethods, but the code I read using something like:

class_methods do
  def **** 
  end
end
like image 234
Adam Lee Avatar asked Oct 25 '15 04:10

Adam Lee


People also ask

How do concerns work in Rails?

Concerns allow us to include modules with methods (both instance and class) and constants into a class so that the including class can use them. The code inside the included block is evaluated in the context of the including class.

What is ActiveSupport concern?

ActiveSupport's Concern module allows us to mix in callbacks, class and instance methods, and create associations on target objects. This module has an included method, which takes a block, as well as an append_features method and class_methods block, which you can read about in the source code.

What is the difference between module and concern?

Concern can appear somewhere as model, controller and at here you can write module for yourself. And with general module is write in lib folder. Both can be used by way include or extend into a class.

What is the difference between extend and include in Ruby?

In simple words, the difference between include and extend is that 'include' is for adding methods only to an instance of a class and 'extend' is for adding methods to the class but not to its instance.


1 Answers

ActiveSupport::Concern provides syntactic sugar for common Ruby patterns for module mixins.

When you are using modules as mixins you can't just use self to declare class methods like you would from a class:

module Foo
  def self.bar
    "Hello World"
  end
 
  def instance_method
    "Hello World"
  end
end

class Baz
  include Foo
end
irb(main):010:0> Baz.bar
NoMethodError: undefined method `bar' for Baz:Class
    from (irb):10
irb(main):011:0> Foo.bar
=> "Hello World"
irb(main):012:0> 

As you can see from the example that actually creates a module method - thats because self is the module. You can use extend instead:

module Foo
  def a_class_method
    "Hello World"
  end
end

class Bar
  extend Foo
end
irb(main):049:0> Bar.a_class_method
=> "Hello World"

But that does not let you declare instance methods in the module. Which is not really that useful.

So the solution is to create an inner module which is commonly named ClassMethods and extend the class when the module is included:

module Foo
  # this is a method thats called when you include the module in a class.
  def self.included(base)
    base.extend ClassMethods
  end

  def an_instance_method
  end
   
  # the name ClassMethods is just convention.
  module ClassMethods
    def a_class_method
      "Hello World"
    end
  end
end

class Bar
  include Foo
end
irb(main):071:0> Bar.a_class_method
=> "Hello World"

This boilerplate code is found in almost every ruby gem/library.

By extending your module with ActiveSupport::Concern you can shorten this to just:

module Foo
  extend ActiveSupport::Concern
  class_methods do
    def a_class_method
      "Hello World"
    end
  end
end

Under the hood ActiveSupport::Concern creates a ClassMethods module and evaluates the block in the context of the module. Dig into the source if you curious about how it actually does this.

like image 54
max Avatar answered Oct 17 '22 02:10

max