1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Rails6 のちょい足しな新機能を試す66(query with large number編)

Posted at

はじめに

Rails 6 に追加されそうな新機能を試す第66段。 今回は、 query with large number 編です。
Rails 6 では、 検索条件の値が Integer などの型の範囲外の値であっても検索できるようになりました。

Ruby 2.6.3, Rails 6.0.0.rc1, Rails 5.2.3 で確認しました。Rails 6.0.0.rc1 は gem install rails --prerelease でインストールできます。

(Rails 6.0.0 がリリースされましたが、確認当時は Rails 6.0.0.rc1 がリリースされた時でした。悪しからず。)

$ rails --version
Rails 6.0.0.rc1

今回は、 User モデルに :bigint を指定した age を追加して、 age の範囲外の値を検索条件にして検索してみます。

プロジェクトを作る

rails new rails6_0_0rc1
cd rails6_0_0rc1

model を作る

User モデルを作ります。
name の他に :bigint を指定した age を追加します。

bin/rails g model User name age:bigint

seed データを作る

1件だけですが、 seed データを作成します。

db/seeds.rb
User.create(name: 'Taro', age: 1)

User モデルを修正する

User モデルに scope を5つ作ります。

ここで条件に age の値の範囲に含まれない大きな値と小さな値を指定します。

app/models/user.rb
class User < ApplicationRecord
  LARGE = 9223372036854775808
  SMALL = -9223372036854775809
  scope :age_in_large, -> { where(age: [1..LARGE]) }
  scope :age_eq_large, -> { where(age: LARGE) }
  scope :age_not_eq_large, -> { where.not(age: LARGE) }
  scope :age_in_small, -> { where(age: [SMALL..1]) }
  scope :age_in_small_large, -> { where(age: [SMALL..LARGE]) }
end

seed データを登録します。

$ bin/rails db:create db:migrate db:seed

rails console で確認する

rails console で確認してみます。

irb(main):001:0> User.age_in_large
  User Load (0.4ms)  SELECT "users".* FROM "users" WHERE "users"."age" >= $1 LIMIT $2  [["age", 1], ["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<User id: 1, name: "Taro", age: 1, created_at: "2019-07-26 21:21:06", updated_at: "2019-07-26 21:21:06">]>
irb(main):002:0> User.age_eq_large
  User Load (0.5ms)  SELECT "users".* FROM "users" WHERE 1=0 LIMIT $1  [["LIMIT", 11]]
=> #<ActiveRecord::Relation []>
irb(main):003:0> User.age_not_eq_large
  User Load (0.5ms)  SELECT "users".* FROM "users" WHERE 1=1 LIMIT $1  [["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<User id: 1, name: "Taro", age: 1, created_at: "2019-07-26 21:21:06", updated_at: "2019-07-26 21:21:06">]>
irb(main):004:0> User.age_in_small
  User Load (0.3ms)  SELECT "users".* FROM "users" WHERE "users"."age" <= $1 LIMIT $2  [["age", 1], ["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<User id: 1, name: "Taro", age: 1, created_at: "2019-07-26 21:21:06", updated_at: "2019-07-26 21:21:06">]>
irb(main):005:0> User.age_in_small_large
  User Load (0.8ms)  SELECT "users".* FROM "users" WHERE 1=1 LIMIT $1  [["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<User id: 1, name: "Taro", age: 1, created_at: "2019-07-26 21:21:06", updated_at: "2019-07-26 21:21:06">]>

ここで、実際に発行されているSQLに注目してください。SQL自体には、 -9223372036854775809 や 9223372036854775808 は登場しません。
これは、 age の値として、 -9223372036854775809 や 9223372036854775808 は、あり得ない範囲外の値なので、検索条件に含まなくても良いためです。
工夫されてますね。 User.age_not_eq_large の条件の where 1=1 など、なるほどと思ってしまいます。

Rails 5では

検索条件の値が、 age の範囲に収まらないため、 RangeError になってしまいます。

irb(main):001:0> User.age_eq_large
Traceback (most recent call last):
ActiveModel::RangeError (9223372036854775808 is out of range for ActiveModel::Type::Integer with limit 8 bytes)
irb(main):002:0> User.age_not_eq_large
Traceback (most recent call last):
ActiveModel::RangeError (9223372036854775808 is out of range for ActiveModel::Type::Integer with limit 8 bytes)
irb(main):003:0> User.age_in_large
Traceback (most recent call last):
ActiveModel::RangeError (9223372036854775808 is out of range for ActiveModel::Type::Integer with limit 8 bytes)
irb(main):004:0> User.age_in_small
Traceback (most recent call last):
ActiveModel::RangeError (-9223372036854775809 is out of range for ActiveModel::Type::Integer with limit 8 bytes)
irb(main):005:0> User.age_in_small_large
Traceback (most recent call last):
ActiveModel::RangeError (-9223372036854775809 is out of range for ActiveModel::Type::Integer with limit 8 bytes)

試したソース

試したソースは以下にあります。
https://github.com/suketa/rails6_0_0rc1/tree/try066_query_with_large_number

参考情報

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?