LoginSignup
2
4

More than 5 years have passed since last update.

has_many みたいな、クラス定義時に使えるメソッドの実装方法

Posted at

Ruby on Rails の ActiveRecord についてくる has_many メソッドは、モデルクラス間の関連を宣言的に書けて大変便利だと思います。
自分でも同じように宣言的に書けるメソッドを定義したいと思ったことがある人は多いでしょう。
本記事では、このようなメソッドの定義方法について簡単に紹介したいと思います。

class Post < ActiveRecord::Base
  # こんな風に関連を宣言的に書けて便利ですね。
  # 本記事ではこのようなメソッドの定義方法を見て行きます。
  has_many :comments
end 

時間がない人向け

class Base
  class << self
    attr_accessor :_label

    def label label
      self._label = label
    end
  end

  def to_s
    "<#{self.object_id}@#{self.class._label}>"
  end
end


class Conc < Base
  label "とあるクラス"
end

puts Conc.new.to_s # <2939193@とあるクラス>

どのように定義するか

リファレンスによれば、クラス定義式の中では self はそのクラスになります。
なお、通常(トップレベル)での selfmain オブジェクトです。

実験してみましょう。

puts self # main

class Hoge
  puts self # Hoge
end

と、いうわけで、メソッドを定義してあげると、クラス定義式中でそのメソッドを使うことが可能となります。

class Hoge
  def self.piyo
    puts 47
  end

  piyo
end

引数をとって値を保存するにはクラス変数に保存してあげればよいでしょう。

class Hoge
  def self.piyo val
    @val = val # ここは @@val にしないでくださいね。
    # ややこしいですが、Hogeのクラス変数は「Hoge というクラス」のインスタンス変数とほぼ同義だからです。
  end

  def self.fuga
    @val || ''
  end

  piyo 'aaa'
end

puts Hoge.fuga # 'aaa'

モジュールにした場合は Module#include が使えないことにご注意ください。特異クラスに対する Module#include を実現するものとして Object#extend がありますので、そちらを使います。

module M
  def m1 val
    @val = val
  end

  def m2
    @val || ''
  end
end

class C
  extend M
  m 'test'
end

puts C.m2 # 'test'
2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4