scopeとは
よく利用する検索条件に名前をつけてひとまとめにしたもの。
railsガイドでは以下のように解説されています。
スコープを設定することで、関連オブジェクトやモデルへのメソッド呼び出しとして参照される、よく使用されるクエリを指定することができます。スコープでは、where、joins、includesなど、これまでに登場したすべてのメソッドを使用できます。どのスコープメソッドも、常にActiveRecord::Relationオブジェクトを返します。このオブジェクトに対して、別のスコープを含む他のメソッド呼び出しを行なうこともできます。
scopeの書き方
class Book < ApplicationRecord
scope :costly, -> { where("price > ?", 3000) }
end
scopeの第一引数にメソッド名、第二引数にProcオブジェクト(のラムダ)を定義することで、コントローラーやモデルでBook.costly
と書いたとき、Book.where("price > ?", 3000)
と書いたのと同義になります。これによるメリットは以下の2つです。
- 繰り返し利用できる
- 可読性が向上する
何度もクエリを書かなくてよくなるのに加えて、Book.costly
とあれば、高価な本を探しているんだなとひと目で分かります。
また、引数を渡すこともできます。
class Book < ApplicationRecord
scope :written_about, ->(theme) { where("name like(?)", "%#{theme}%") }
end
scopeを定義した際の返り値のクラスはActiveRecord::Relationとなるので、scopeをメソッドチェーンでつなげたり、Query Interfaceを呼び出すこともできる。
Book.costly.written_about("ハリーポッター").limit(1)
=> #<ActiveRecord::Relation [
#<Book id: 1, name: "賢者の石", published_on: "1999-10-21", price: 4000>
]>
ブロックが複数行に渡る場合
scopeの第二引数はProcオブジェクトのラムダを使います。ブロックが複数行に渡る場合は下のような書き方が一般的です。
scope :written_about, lambda { |theme|
return if theme.blank?
where("name like(?)", "%#{theme}%")
}
以上
補足
Procオブジェクトとは
ブロックをオブジェクト化したProcクラスのインスタンスです。
hello_proc = Proc.new { "hello" }
hello_proc.call
=> "hello"
Procオブジェクトの作成方法
Proc.new { |a, b| a + b }
proc { |a, b| a + b }
->(a, b) { a + b }
lambda { |a, b| a + b }
厳密には上2つと下2つのオブジェクトは異なります。下2つはラムダと呼ばれ、scopeの第二引数で使っているものです。ラムダは引数のチェックがより厳密です。検索条件で渡ってくる引数は決まっているため、ラムダを使っていました。
add_proc = Proc.new { |a, b| a.to_i + b.to_i }
add_proc(10)
#=> 10
add_lambda = ->(a, b) { a.to_i + b.to_i }
add_lambda(10)
#=> ArgumentError: wrong number of arguments (given 1, expected 2)
Procオブジェクトの実行方法
add_proc = Proc.new { |a, b| a + b }
add_proc.call(10, 20)
add_proc.yield(10, 20)
add_proc.(10, 20)
add_proc[10, 20]
参考
https://railsguides.jp/active_record_querying.html#%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%97
パーフェクトRuby on Rails