Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

ActiveRecordで関連しているモデルのコレクションに対してメソッドを定義する

More than 5 years have passed since last update.

Association extensions

Parent has_many childrenみたいな関係のモデルでparent.childrenに対してメソッドを定義したいことがよくあります。
たとえばchildrenの属性によって絞りこんだり(children.malesで性別が男性のchildのみを返す)、またはchildrenに関連する他のモデルを取得したり(children.schoolsでchildrenが通っている学校のコレクションを返す)など。

そんなとき、Association extensionsという機能を使うと上手くメソッドを定義できます。

Association extensionとは、関連として取得するモデルのコレクション(ActiveRecord_Associations_CollectionProxy)を自分が定義したメソッドやモジュールで拡張することが出来る機能のことです。

例題のモデル定義

以下のようなモデル定義があるとします。

class Parent < ActiveRecord::Base
  has_many :children
end

class Child < ActiveRecord::Base
  has_many :parents
  belongs_to :school
end


class School < ActiveRecord::Base
  has_many :children
end


parent = Parent.first
parent.children #=> [Child, Child, Child]
parent.children.first.school #=> School

メソッドで拡張する

ではchildrenを性別が男性かどうかによってフィルタするメソッドmalesを定義して、拡張してみます。

class Parent < ActiveRecord::Base
  has_many :children do
    def males
      self.where(:gender, 'male')
    end
  end
.
.
.
end

Parent.first.children.males #=> [Child, Child]

上記のように定義すると以下のようにするchildrenに対して定義したmalesメソッドを呼ぶことができます。
ちなみにmalesメソッド内でのselfはchildrenになります。

モジュールで拡張する

上記のようにメソッドで拡張することも出来ますが、childrenはSchoolモデルでも使われているため同じメソッドを重複して定義することになります。
そういうときはchildrenを拡張するモジュールを作り、そのなかでメソッドを定義すると重複を失くすことが出来ます。

module ChildrenExtension
  def males
    self.where(:gender, 'male')
  end
end

class Parent < ActiveRecord::Base
  has_many :children, -> { extending ChildrenExtension }
.
.
.
end

class School < ActiveRecord::Base
  has_many :children, -> { extending ChildrenExtension }
end


Parent.first.children.males #=> [Child, Child]
School.first.children.males #=> [Child, Child]

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