Help us understand the problem. What is going on with this article?

DEPRECATION WARNING: Class level methods will no longer inherit scoping from `fixed` in Rails 6.1.

警告の意味

※ どのコードも意味が無く申し訳ないですが、生成されるSQLの問題なので意味は伝わると信じてます・・・いいサンプルコードが思いつかなくてすいません。

Rails5から6にアップグレードしたらこんな警告が出るようになった。

DEPRECATION WARNING: Class level methods will no longer inherit scoping from `fixed` in Rails 6.1. To continue using the scoped relation, pass it into the block directly. To instead access the full set of models, as Rails 6.1 will, use `ShiftUser.unscoped`. (called from block in <class:ShiftUser> at /home/circleci/test_dir/app/models/shift_user.rb:10)

問題のコードはこんな感じ。

class ShiftUser < ApplicationRecord
  scope :fixed, -> {
    ShiftUser.reflected.or(ShiftUser.failed)
  }

このコード、私のミスで変なコードになってます。本来意図したコードは下記の感じです。

class ShiftUser < ApplicationRecord
  enum status: { building: 1, reflected: 2, failed: 3 }
  scope :fixed, -> {
    reflected.or(failed)
  }

で、現状6.0まではどっちも同じSQLが発行されます。

ShiftUser.where(user_id: [1,2]).fixed
# SELECT `shift_user`.* FROM `shift_user` WHERE `shift_user`.`user_id` IN (1, 2) AND (`shift_user`.`status` = 2 OR `shift_user`.`status` = 3)

ブロック内でShiftUser.reflectedとクラスメソッドから呼んでいるのだからActiveRecordRelationがリセットされそうな感じがするのですが、継承されてるんですね。

この挙動が気持ち悪いので6.1から変えるという話だと思います。たぶんこの辺が関連ISSUEだと思われます。

https://github.com/rails/rails/pull/32380
https://github.com/rails/rails/pull/35186
https://github.com/rails/rails/pull/35280

どう治すか?

ほとんどの場合下記のように修正すれば問題ないでしょう。

class ShiftUser < ApplicationRecord
  scope :fixed, -> {
    reflected.or(failed)
  }

このように直接メソッド呼ぶようにしておかないと6.1になった時に挙動が変わりますね。現状6.0以前バージョンで6.1の挙動を実現したい場合はShiftUser.unscoped使います。こんな感の2フェーズクエリーでたまに使うかも。

class ShiftUser < ApplicationRecord
  scope :some_scope, -> {
    where(user_id: ShiftUser.unscoped.pluck(:user_id))
  }

現状でこのコードを

class ShiftUser < ApplicationRecord
  scope :some_scope, -> {
    where(user_id: ShiftUser.pluck(:user_id))
  }

こう書いてしまうと下記のように、内側のSQLにもwhere(user_id: [1,2])がくっついて(たぶん)意図してないコードになります。

ShiftUser.where(user_id: [1,2]).some_scope
# (0.3ms)  SELECT `shift_user`.`user_id` FROM `shift_user` WHERE `shift_user`.`user_id` IN (1, 2)
#   ShiftUser Load (0.4ms)  SELECT `shift_user`.* FROM `shift_user` WHERE `shift_user`.`user_id` IN (1, 2) AND 1=0
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした