scopeとは
スコープを設定することで、絞り込み条件、すなわちクエリー用のメソッドの連続した呼び出し部分をまとめて名前をつけ、カスタムのクエリー用メソッドとして使うことができます。
複雑なSQLを何度も書かなくてよくなります。繰り返し利用される絞り込み条件をスッキリ読みやすくでき、保守性に優れて、レビュアーにとっても読みやすくなります。
同じことがcontrollerでもできるのですが『Skinny Controller, Fat Model(コントローラーのコード量を少なくして、モデルを分厚くする)』という書き方が推奨されています。 このような背景から、ファットモデルという設計が目指すべき設計ということになります。
scopeを使った例
Railsガイドの例を使って説明していきます。
クラスの内部でscopeメソッドを使用し、スコープが呼び出されたときに実行して欲しいクエリをそこで渡します。
class Article < ApplicationRecord scope :published, -> { where(published: true) } end
scopeはクラスメソッドの定義と完全に一致しています。どちらの形式を使用しても構いません。
class Article < ApplicationRecord def self.published where(published: true) end end
scope内でチェインすることも可能です。
class Article < ApplicationRecord scope :published, -> { where(published: true) } scope :published_and_commented, -> { published.where("comments_count > 0") } end
scopeを使った呼び出し
category = Category.first category.articles.published # => [このカテゴリに属する、公開済みの記事]
引数を受け取ったscope
article.rb
scope :by_category, ->(category_id) { where(category_id: category_id) }
search_articles_form.rb
relation = relation.by_category(category_id) if category_id.present?
このように書いておけば、選択したカテゴリーに該当する記事を検索できるようになる。
scope :title_contain, ->(word) { where('title LIKE ?', "%#{word}%") }
title_words.each do |word| relation = relation.title_contain(word) end private # タイトルの検索内容を配列に入れている。 def title_words title.present? ? title.split(nil) : [] end
入力内容に該当する記事を検索できるようになる
URL