はじめに
(多分)Rails 6 に追加された新機能を試す第71段。 今回は、 implicit_order_column
編です。
Rails 6 では、 first
や last
で使われるソートのカラムを implicit_order_column
で指定できるようになっています。
これは、id を UUID にしていた場合に、 first
や last
が予測できる結果となるようにするためのようです。
(Rails 6.0.0 がリリースされましたが、確認当時は、 Rails 6.0.0.rc2 が最新でした。悪しからず )
Ruby 2.6.3, Rails 6.0.0.rc2, PostgreSQL 10.7 で確認しました。Rails 6.0.0.rc2 は gem install rails -v 6.0.0rc2 --prerelease
でインストールできます。
$ rails --version
Rails 6.0.0.rc2
今回は、 User モデルを作成して rails console
を使って確認します。
プロジェクトを作る
rails new rails_sandbox --database postgresql
cd rails_sandbox
User モデルを作る
bin/rails g model User name
id を UUID にする
id を UUID にするために、マイグレーションのファイルを変更します。
class CreateUsers < ActiveRecord::Migration[6.0]
def change
enable_extension 'pgcrypto' unless extension_enabled?('pgcrypto') #この行を追加
create_table :users, id: :uuid do |t| # id: :uuid オプションを追加
t.string :name
t.timestamps
end
end
end
seed データを作成する
seed データを作成します。 name の昇順にデータを登録します。
User.create(name: 'Andy')
User.create(name: 'Bob')
User.create(name: 'Cindy')
マイグレーションを実行し seed データを登録する
bin/rails db:create db:migrate db:seed
rails console で確認する
rails console
で確認します。
User.first
を実行してみます。
irb(main):001:0> User.first
User Load (0.3ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT $1 [["LIMIT", 1]]
=> #<User id: "5da612ca-f055-4678-9c87-927b0a1a28d2", name: "Cindy", created_at: "2019-08-03 22:24:51", updated_at: "2019-08-03 22:24:51">
結果が Cindy になってしまいました。 (結果は必ず Cindy になるとは限りません。)
SQL を確認すると id
でソートされていることもわかります。
User.last
を実行してみます。
irb(main):002:0> User.last
User Load (0.5ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT $1 [["LIMIT", 1]]
=> #<User id: "fe31d9a5-8de0-4d35-8a6f-183902f2884b", name: "Bob", created_at: "2019-08-03 22:24:51", updated_at: "2019-08-03 22:24:51">
結果が Bob になりました。
SQLを確認すると id
の降順にソートした最初のレコードが検索されているのがわかります。
implicit_order_column を使う
User モデルを変更して implicit_order_column で :name
を指定してみます。
class User < ApplicationRecord
self.implicit_order_column = :name
end
rails console で確認する
修正を反映させるため reload!
します。
irb(main):003:0> reload!
Reloading...
=> true
User.first
の結果は、 Andy になります。 name
の昇順でソートされていることがわかります。
irb(main):004:0> User.first
User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."name" ASC LIMIT $1 [["LIMIT", 1]]
=> #<User id: "cc7ff0b1-4dc3-47f4-a5cd-259a804c9690", name: "Andy", created_at: "2019-08-03 22:24:51", updated_at: "2019-08-03 22:24:51">
User.last
の結果は、 Cindy になります。 name
の降順でソートされていることがわかります。
irb(main):005:0> User.last
User Load (0.6ms) SELECT "users".* FROM "users" ORDER BY "users"."name" DESC LIMIT $1 [["LIMIT", 1]]
=> #<User id: "5da612ca-f055-4678-9c87-927b0a1a28d2", name: "Cindy", created_at: "2019-08-03 22:24:51", updated_at: "2019-08-03 22:24:51">
複数カラムの指定はできない
self.implicit_order_column = %i[name created_at]
とした場合は、 ActiveRecord::StatementInvalid エラーになりました。
まあ、そりゃそうですよね。 複数形 ( implicit_order_columns
) じゃないですもんね。
irb(main):011:0> User.first
Traceback (most recent call last):
2: from (irb):11
1: from (irb):11:in `rescue in irb_binding'
ActiveRecord::StatementInvalid (PG::UndefinedColumn: ERROR: column users.[:name, :created_at] does not exist)
LINE 1: SELECT "users".* FROM "users" ORDER BY "users"."[:name, :cre...
^
試したソース
試したソースは以下にあります。
https://github.com/suketa/rails_sandbox/tree/try071_implicit_order_column