What does class_methods do in concerns?

class_methods is used to add class methods to the model used by the concern.

A typical module looks like this:

module M
  def self.included(base)
    base.extend ClassMethods
  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

  class_methods do
    ...
  end
end

As Oleg Antonyan pointed out, from the source code, we know that it's going to use ClassMethods module under the hood.

Reference: http://api.rubyonrails.org/classes/ActiveSupport/Concern.html


It's just for convenience. module ClassMethods is pure Ruby, but class_methods is defined in ActiveSupport::Concern for convenience. If you look at a source code you'll find that class_methods does exactly the same thing

  # activesupport/lib/concern.rb
  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

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.