[Rails]モデルのscopeメソッド
モデルのscopeメソッド
モデルにおけるscope
とはActiveRecordの機能の一つです。
モデル側で共通の条件式(クエリ処理)に名前を付けて定義し、その名前でメソッドのように呼び出すことができる仕組みのことです。
例)モデルにscope定義
(published
カラムはtrue
かfalse
で公開
・非公開
を管理)
class Blog < ApplicationRecord
scope :published, -> { where(published: true) }
end
呼び出し
Blog.published
scopeを使うメリット
-
条件式に名前を付けられるので直感的なコードになる
※ scopeを使わない場合Blog.where(published: true)
※ scopeを使った時(条件式はモデルに
published
という名前で定義済み)Blog.published
-
共通化により修正箇所が少なくて済む
モデルにscope定義# blogsテーブルのpublishedがtureの記事を取得 class Blog < ApplicationRecord scope :published, -> { where(published: true) } end
↓ 上記のコードに
limit
を追加したい時# scope定義のこの部分だけ変更するだけで済む。 class Blog < ApplicationRecord scope :published, -> { where(published: true).limit(3) } end # 呼び出しはBlog.publishedで変わらない
-
記述コードが短くなる
条件式はscopeを使わなくても、クラスメソッドとして定義できるが、コードが長くなってしまう。
# 条件式はscopeを使って定義している class Blog < ApplicationRecord scope :published, -> { where(published: true) } end # scopeを使わずにクラスメソッドとしても定義できるが、、 class Blog < ApplicationRecord def self.published where(published: true).limit(2) end end
scopeメソッドの基本
下記のように定義します。
class モデル名 < ApplicationRecord
scope :スコープの名前, -> { 条件式 }
end
-
第一引数にシンボルを使ってスコープの名前を指定します。
-
第二引数の
-> { 条件式 }
はlambdaと言い、処理の中でメソッドを定義してくれます。 -
->
(アロー関数)はlambdaのリテラルです。下記のような動きをします。
引数を定義すると、呼び出すときにブロックに渡すことができます。# 定義 foo = -> (x) { x + x } # 呼び出し foo[5] # => 10 foo.(5) # => 10 foo.call 5 # => 10 # 通常のlambdaの書き方 bar = lambda { |x| x + x } bar.call 5 # => 10
class Blog < ApplicationRecord
scope :published, -> { where(published: true).limit(2) }
end
- blogsテーブルから「公開」の記事を取得。さらに上限を2までにする。
引数を渡す
scopeメソッドは下記のように->
の後ろに引数を定義すると、ブロックに引数を渡すことができます。
class モデル名 < ApplicationRecord
scope :スコープの名前, -> (引数){ 条件式 }
end
引数を利用すると、scopeのpublished
を呼び出すときに、引数を渡せるので、取得上限件数をその都度変更できます。
# blogsテーブルから「公開」の記事を取得。さらに上限を2までにする。
class Blog < ApplicationRecord
scope :published, -> (count){ where(published: true).limit(count) }
end
# 呼び出し 上限が3の「公開」記事を取得できる。
Blog.published(3)
この様に引数を使うことで、汎用性のある条件式をつくることができます。
scopeを使ってメソッドチェーンを簡潔に
例としてBlogコントローラのindexで@boards
がwhere(published: true).order(created_at: :desc)
のようにBlogを呼び出します。
class BlogController < ApplicationController
def index
@blogs = Blog.where(published: true).order(created_at: :desc)
end
end
published
がtrue
のblogのcreated_at
カラムを降順に並び替えて取得しています。
これで呼び出すことはできるが、where
とorder
メソッドが連結しているので若干読みづらくなっています。
これをscopeメソッドを用いて「published
」、「sorted
」、「recent
」という3つのscopeを定義してみます。
class Blog < ApplicationRecord
# publishedカラムがtrueのものを取得
scope :published, -> { where(published: true) }
# created_atカラムを降順で並び替え
scope :sorted, -> {order(created_at: :desc)}
# publishedがtrueのものを降順で並び替え
scope :recent, -> {published.sorted}
end
scopeで定義すると、再利用が可能なので毎回同じクエリメソッドを使う場合はscope定義したほうがコードもスッキリして読みやすくなります。
class BlogController < ApplicationController
def index
# @blogs = Blog.where(published:true).order(created_at: :desc)
@blogs = Blog.recent
end
end
Discussion