2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Railsのscopeの良くない書き方

Posted at

はじめに

Railsのモデルでよくscopeを使用した記述をします。
scopeの使い方が悪く、予期せぬクエリが呼ばれていたので備忘録として残します。

良くなかった書き方

モデル名やscope名は仮で入れています。

class Model
  scope :prev_staff_id, ->(customer_id) {
    where(customer_id: customer_id)
      .order(updated_at: :desc)
      .limit(1)
      .pick(:staff_id)
  }
end

Model.prev_staff_idとすれば、以前のスタッフIDを返すことを期待しています。
limit(1)を指定して、staff_idを指定しているので一見クエリに問題はなさそうです。

問題点

①メソッドチェーンできるようにしておく

メソッドチェーンは今回のprev_staff_idに加えて、activeのような別のスコープが合ったときに以下のように常ゲテ使用することを言います。

Model.prev_staff_id.active

ですが、prev_staff_idの返り値はstaff_idのため、そもそもscopeの使い方として適しておりませんでした。

②思わぬクエリが呼ばれていた

今回の失態に気づくきっかけにもなったのですが、アプリの読み込みに想定以上の時間がかかっておりました。
よくログを見てみると、ある状態で操作するとあるモデルの全件取得クエリが確認できました。

デバッグすると例示しているscopeに問題があるとわかり、scopeを誤った使い方をするとlimitされずに全件取得のクエリが走っていたのでした。

対処法

いくつか対応の方法はありますがクラスソッドに変更するのが無難なのではないでしょうか。

class Model
  def self.prev_record(customer_id)
    where(customer_id: customer_id)
      .order(updated_at: :desc)
      .first
  end
end
prev_staff_id = Mode.prev_record.staff_id

まとめ

  • クラスソッド、scopeの使い分けを考えて実装する必要がある
  • 誤った使い方をすると想定しないクエリが発生してしまうので注意が必要である
  • 問題が起きたときはログを確認して確実に対処していく
2
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
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?