Help us understand the problem. What is going on with this article?

Rails の module ClassMethods がやっている事

More than 5 years have passed since last update.

Rails のコードを読んでいると、module ClassMethods って多く書かれている事が分かると思いますが、こいつが何をやっているのかを話していきます。

module ClassMethods を説明する前に、まず、以下のような Module と Class を定義します。

module ModuleA
  def self.class_method_a
    'class_method_a'
  end

  def instance_method_a
    'instance_method_a'
  end
end

class ClassA
  include ModuleA
end

そして、次に include した、インスタンスメソッドとモジュールメソッドを実行してみると

ClassA.new.instance_method_a #=> "instance_method_a"
ClassA.class_method_a        #=> NoMethodError

このように class_method_aNoMethodError になる事が分かります。
class_method_a はあくまで ModuleA の特異メソッドなので、利用することが出来ないのです。

そこで、以下のようにします。

module ModuleB
  def self.included(klass)
    klass.extend ClassMethods
  end

  module ClassMethods
    def class_method_b
      'class_method_b'
    end
  end
end

class ClassB
  include ModuleB
end

ClassB.class_method_b #=> "class_method_b"

included をオーバーライドして、ModuleBinclude する際に、ClassBClassMethodsextend しています。こうすることで、クラスメソッドとして使えるようになります。

ちなみに、class_method_bextend するために Module で囲っているだけなので、Module 名に意味はありません。ただ、慣習的に module ClassMethods とするそうです。

以上が module ClassMethods の意味です。

しかし、Rails のコードを読んでいると、included を使って ClassMethodsextend している箇所は見つかりません。

module ActiveSupport
  module Configurable
    extend ActiveSupport::Concern

    ...

    module ClassMethods
      ...

そして、代わりに ActiveSupport::Concernextend していることに気がつきます。そこで、実際にマネして Module を次のようにしてみると、

module ModuleC
  extend ActiveSupport::Concern

  module ClassMethods
    def class_method_c
      'class_method_c'
    end
  end
end

class ClassC
  include ModuleC
end

ClassC.class_method_c   #=> "class_method_c"

確かにクラスメソッドとして、使えます。

これは ActiveSupport::Concernappend_features 内で ClassMethodsextend するようにオーバーライドしているためです。(append_featuresinclude の手前で呼び出されるメソッドです)
そのため、Module に ActiveSupport::Concernextend すれば、自動的にその Module が include された際に、ClassMethodsextend します。

つまり、extend ActiveSupport::Concern としておけば、ClassMethods は全てクラスメソッドとして、使えるようになります。

ちなみに、Rails 4.2 以降は以下のように class_methods で囲みます。

module ModuleD
  extend ActiveSupport::Concern

  class_methods do
    def class_method_d
      'class_method_d'
    end
  end
end

class ClassD
  include ModuleD
end

ClassD.class_method_d   #=> "class_method_c"

便利ですね。

長々と書きましたが、最後に、誤解を恐れずに一言で結論づけると module ClassMethodsinclude した際にクラスメソッドとして、利用できるというサインです。

pekepek
sansan
法人向け名刺管理サービスSansan及び個人向け名刺管理サービスEightを企画・開発・販売するベンチャー
http://jp.corp-sansan.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした