はじめに
Railsを学習していて、**「モデルのscopeってどうやって使うんだろう?」**となったことがありました。Railsのモデルのscopeはどのような場面で、どうやって使うのかについて説明して行こうと思います。
modelのscopeとは
そもそもmodelのscopeとは、Active Recordの機能の一部です。以下Ruby on Rails ガイドより
スコープを設定することで、関連オブジェクトやモデルへのメソッド呼び出しとして参照される、よく使用されるクエリを指定することができます。スコープでは、where、joins、includesなど、これまでに登場したすべてのメソッドを使用できます。どのスコープメソッドも、常にActiveRecord::Relationオブジェクトを返します。このオブジェクトに対して、別のスコープを含む他のメソッド呼び出しを行なうこともできます。
単純なスコープを設定するには、クラスの内部でscopeメソッドを使用し、スコープが呼び出されたときに実行して欲しいクエリをそこで渡します。
上記を簡潔にするとモデルのscopeとは複数のクエリをまとめたメソッドになります。
modelのscopeを使うと使わないとでは何が違うか?
実際にUserを例に説明して行こうと思います。
Userコントローラーのindex内で@users
がwhere(deleted: false).order(created_at: :desc)
のようにUserを呼び出しています。(deletedカラム
がfalseの時、created_atカラム
を降順で呼び出す)しかし、where
やorder
のクエリメソッドが連結しています。これでも呼びだせるため良いですが、メソッドが連結しているため若干読みづらいです。
class UsersController < ApplicationController
...
def index
@users = User.where(deleted: false).order(created_at: :desc)
end
...
end
Userモデルで以下のように**「active」、「sorted」、「recent」**という3つのscopeを定義しましょう。
class User < ApplicationRecord
...
# deletedカラムがfalseであるものを取得する
scope :active, -> { where(deleted: false) }
# created_atカラムを降順で取得する
scope :sorted, -> { order(created_at: :desc) }
# activeとsortedを合わせたもの
scope :recent, -> { active.sorted }
...
end
scopeは再利用が可能です。そのため、繰り返し何度も呼び出す際は毎回クエリメソッドを連結で呼び出すよりも、scopeを定義したほうがコードがスッキリして読みやすくなるということです。それなら以下のようにしても良いのでは?と思われる方もいるかと思います。
scope :recent, -> { where(deleted: false).order(created_at: :desc) }
なぜ、3つのscopeに分けたかというと、再利用という点に着目した際にwhere(deleted: false).order(created_at: :desc)
とあらかじめ連結しておくよりもwhere(deleted: false)
とorder(created_at: :desc)
に分けておくことにより、個々でつかうことが可能となるため広く利用可能になるからです。また、active
とsorted
を合わせたrecent
を定義することでコントローラーから簡単に呼び出すごとができます。
class UsersController < ApplicationController
...
def index
@users = User.recent
end
...
end
比較するとscopeを定義して、複数のクエリを集約したメソッドrecent
を作ったほうが簡潔に書けると思います。
class UsersController < ApplicationController
...
def index
# scope recentを定義しなかった場合
@users = User.where(deleted: false).order(created_at: :desc)
# scope recentを定義した場合
@users = User.recent
end
...
end
まとめ
- モデルのscopeを定義することにより、複数のクエリを一つのメソッドとしてまとめることができる。
- コントローラーで複数のクエリを書くよりもscopeを使えば、コードがスッキリする。