環境
Rails 5.2.3
mysql 5.7.28
リテラルについて
例文
def index
@boards = Board.includes(:user).order('created_at DESC')
end
def bookmarks
@bookmarks = current_user.bookmarks.board.includes(:user).order('created_at DESC')
end
改善ポイント
・orderはリテラルではなくscopeで定義すべき
理由
・共通化できるクエリはscopeでメソッドのように定義すべき
・クエリはできるだけリテラルで使わないほうが良い
リテラル=変数やメソッド化していないただのベタ書きした文字や数字
メリット
・任意のメソッド名でどのような効果を持つかわかりやすくなる
・探す場所が1箇所に絞られ、リファクタリング容易(保守性)、データベースパフォーマンスの最適化(読み込みスピードUP)が図れる
・IDEの構文チェックがうまく走らないことがあり、ミスに気づけなくなることがある。
scope
共通的に使うクエリーをメソッドのように定義することができる便利な機能。
scope :new_order, -> { order(created_at: :desc) }
def index
@boards = Board.includes(:user).new_order
end
def bookmarks
@bookmarks = current_user.bookmarks.board.includes(:user).new_order
end
このようにscopeを使用することで先ほどあげたメリットがある。
しかし、システムが大きくなるほどscopeの数が増えていき見通しが悪くなる。
そんな時にActiveSupport::Conernを使ってmoduleに機能を切り出す。
ActiveSupport::Concern
共通処理をモジュールとして切り出し、インクルードすることでモジュールを使用。
例文
scope :new_order, -> { order(created_at: :desc) }
scope :new_order, -> { order(created_at: :desc) }
複数のモデルで同じscopeが定義されている時、ActiveSupport::Concernでまとめる。
引用
- app/models/concerns/以下のモジュールファイルを作成する
- ActiveSupport::Concernモジュールをextendで取り込む
- includedブロック内でscopeを宣言する
- モデル側でモジュールをincludeする
require 'active_support'
module Hoge
extend ActiveSupport::Concern
included do
scope :new_order, -> { order(created_at: :desc) }
end
end
include Hoge
まとめ
参考資料
Rails: モデルの外では名前付きスコープだけを使おう(翻訳)
scopeをActiveSupport::Concernに分割する
[Rails] ActiveSupport::Concern の存在理由