LoginSignup
348
302

More than 3 years have passed since last update.

Railsでよく利用する、Scopeの使い方。

Last updated at Posted at 2018-06-11

Scope(スコープ)とは

scopeとは、クラスメソッドを使う際、可読性を保つためにあるものです。

例えば、あるUserのidを降順にし、かつ5つだけ表示させたい場合、以下のようなメソッドを使うことになります。

  User.order(id: desc).limit(5)

しかし、このような記述をもしいろんなところで使うとした場合、長ったらしいメソッドチェーンを書くのは面倒だし、コントローラ側で使うときに可読性が落ちます。

そういったときに使うのがscope。
上と同じ式を一つのメソッドとして定義できます(ここでいうrecent)

user.rb
class User < ApplicationRecord
  scope :recent, -> { order(id: :desc).limit(5) }
end
users/controller.rb
class UsersController < ApplicationController

def index
  @users = User.recent
end

これでコントローラ側でもUser.recentを使えるようになり、より簡潔になりましたね。

また、スコープに引数を渡すことも可能です。

user.rb
class User < ApplicationRecord
  scope :recent, -> (count) { order(id: :desc).limit(count) }
end
users/controller.rb
class UsersController < ApplicationController

def index
  @users = User.recent(10)
end

これで、コントローラ側でUser.recent(10)を呼べば最新の10件が取得できるようになります。

スコープは簡潔に、使いやすく

Modelを呼ぶ際、どこからでも使えて便利なスコープですが、そのどこからでも使えるという部分において考慮すべき点があります。
それは、scope側をシンプルに記述してあげるという点です。

というのも、コントローラによってscopeに渡す値も違うからです。

例えば、国別でUserを検索する以下のスコープがあるとします。

scope :serch_user, ->(country) do
  return if country.nil? 
  country == "japan" ? where(country: true) : where(country: false)
end
scope :serch_user, ->(country) do
  return if country.nil? 
  country ? where(country: true) : where(country: false)
end

前者はcountryが"japan"という文字列で条件分岐しているのに対し、後者はcountryがtrueかfalseかによって分岐させています。
この場合、どう考えても単にbooleanで分岐させている後者のスコープの方が使い安いですよね。
前者の場合、わざわざ"japan"という文字でスコープに渡さなければなりません。

まとめ

僕はscopeを作る際、以下のように考えてました。
viewから値を取ってくる → コントローラに渡す → そのままscopeに渡す

しかし、この発想ではそのコントローラでしか扱えないようなscopeになってしまう恐れがあります。 なので、
viewから値を取ってくる → コントローラに渡す → コントローラ側で、scopeで使える形に変換 →  scopeに渡す
という前提でscopeを作る必要があります。
なので、scopeはどのコントローラからでも使いやすく、単純なものにする必要があるのです。
(と、多分いろいろ間違えてるのでご指摘ありましたらよろしくお願いしますm( )m)

348
302
1

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
348
302