0
0

More than 3 years have passed since last update.

モデルのscopeを使ってコードをすっきりさせる!

Last updated at Posted at 2020-08-27

モデルのscopeについて勉強する機会があったので、紹介させていただきます!

Scopeとは、モデルへのメソッド呼び出しとして参照されるクエリに、
名前を付けてひとまとまりにしたものです。

Scopeを定義する

例えば、あるBookのidを降順にし、かつ10件表示したいとします。
その場合、以下のようなメソッドを使います。

Book.order(id: :desc).limit(10)

他にも条件を追加したい時、もっとメソッドを連結させる必要があり、コントローラーの記述量が増えます。
また、あまりにも長いと一見何の処理を行っているか分かりにくくなるかもしれません。

そこでscopeの出番です。

scopeを使うと以下のように書けます。

class Book < ActiveRecord::Base
  scope :recent, -> { order(id: :desc).limit(10) }
end

このように定義しておけば、コントローラーで「Book.recent」という記述が可能になります。

class BooksController < ApplicationController
  def index
    @books = Book.recent
  end
end

scopeは再利用ができるので、コントローラーで毎回クエリメソッドを連結させる必要がなく、
コードがすっきりするので読みやすくなります。

また、scopeは重ねて呼び出すことも可能です。

モデルにscopeを追加して

class Book < ActiveRecord::Base
  scope :recent, -> { order(id: :desc).limit(10) }
  scope :costly, -> { where("price > ?", 2000) }
end

コントローラーで「Book.costly.recent」という記述が可能になります。

class BooksController < ApplicationController
  def index
    @books = Book.costly.recent
  end
end

引数を渡す

スコープには引数を渡すことができます。

class Book < ActiveRecord::Base
  scope :created_before -> (time) { where(" created_at < ?", time) }
end

引数付きのscopeは、クラスメソッドと同様の方法で呼び出すことができます。

Book.created_before(Time.zone.now)

しかし、scopeに引数を渡す方法は、クラスメソッドとして定義する方法でも同じことができます。

class Book < ActiveRecord::Base
  def self.created_before(time)
    where(" created_at < ?", time)
  end
end

ちなみにscopeに引数を渡すよりも、クラスメソッドで定義する方が推奨されています。

結局scopeを使うと何が良いのか

1. クエリに名前を付けられるので、直感的なコードになる

例えば{ where("price > ?", 2000) }に、costlyという名前をつけると簡潔になります。

2. 修正箇所を限定できる

scopeを再利用している場合、scopeの定義自体を修正するだけで済みます。

3. コードの記述量が減る

scopeを使った場合、同じ処理でメソッドを何回も連結させる必要がないので、コードがすっきりします。

最後に

コードはただ動けば終わりではなく、DRY原則に沿って保守しやすいコードを書けるように意識していきたいです。

そのためにもscopeなど知る必要があるので、リファレンスや技術書を積極的に活用していきたいなと思いました!

以上です!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0