ActiveModelのscopeを✅

PF進捗会に参加して、酒ケジュール作成のヒントをもらった。スコープを活用して条件を決めておくことで、提供したいお酒のアルコール度数をグルーピングできるようで。

「お酒の強さがweakだったユーザーの場合はpercentageが0〜7のお酒、strongだったユーザーの場合はpercentageが8以上のお酒」が提供される流れを実装したい。

なので、今回はRailsのscope機能を学習していきたい。

 

scopeとは

スコープを設定することで、関連オブジェクトやモデルへのメソッド呼び出しとして参照される、よく使用されるクエリを指定することができます。スコープでは、wherejoinsincludesなど、これまでに登場したすべてのメソッドを使用できます。どのスコープメソッドも、常にActiveRecord::Relationオブジェクトを返します。このオブジェクトに対して、別のスコープを含む他のメソッド呼び出しを行なうこともできます。

テーブルを関連づけたり、昇順降順で並べ替えるエイリアスを作成することができる。

どう使うのか

下記のように、scopeの後に、エイリアスを用意する。

class Analyze < ApplicationRecord
  ...
    # deletedカラムがfalseであるものを取得する
    scope :active, -> { where(deleted: false) }
    # created_atカラムを降順で取得する
    scope :sorted, -> { order(created_at: :desc) }
    # activeとsortedを合わせたもの
    scope :recent, -> { active.sorted }
  ...
end

scopeはコントローラーで呼び出すことができる。

class AnalyzesController < ApplicationController

  def index
        @analyzes = Analyze.all.sorted
        render json: @analyzes
	end
end

単一責務を持ったscopeを用意することで、再利用性が高まる。

なので、下記のように一気にまとめるのではなく、active,sortedのように分けている。

class AnalyzesController < ApplicationController

  def index
        @analyzes = Analyze.all.where(deleted: false).order(created_at: :desc)
        render json: @analyzes
	end
end

実際に発行されるSQL

Image from Gyazo

実際にポートフォリオに使ってみる

まずは実現したい挙動を言葉にまとめてみる。

「度数が7%未満のお酒をランダムで4件取得する」と「度数が7%超のお酒をランダムで4件取得する」

class Alcohol < ApplicationRecord

  scope :random_weak, ->{ self.where('alcohol_percentage < ?', 7).shuffle[0..4] }

  scope :random_strong, ->{ self.where('alcohol_percentage > ?', 7).shuffle[0..4]  }

end

発行されるSQL

Image from Gyazo

まとめ

  • コントローラーにSQL文を記述する時に、肥大化しそうな匂いがしたらモデルに切り出す。
  • お酒って面白い。

Active Record クエリインターフェイス - Railsガイド

Railsのモデルのscopeを理解しよう - Qiita

Active Model の基礎 - Railsガイド

ActiveRecord でランダムなレコードが(1件または複数件)欲しい | NizLog