5
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?

More than 5 years have passed since last update.

Rails6 のちょい足しな新機能を試す71(implict_order_column 編)

Posted at

はじめに

(多分)Rails 6 に追加された新機能を試す第71段。 今回は、 implicit_order_column 編です。
Rails 6 では、 firstlast で使われるソートのカラムを implicit_order_column で指定できるようになっています。
これは、id を UUID にしていた場合に、 firstlast が予測できる結果となるようにするためのようです。
(Rails 6.0.0 がリリースされましたが、確認当時は、 Rails 6.0.0.rc2 が最新でした。悪しからず :bow:)

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 にするために、マイグレーションのファイルを変更します。

db/migrate/20190803221758_create_users.rb
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 の昇順にデータを登録します。

db/seeds.rb
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 を指定してみます。

app/models/user.rb
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">

複数カラムの指定はできない

app/models/user.rb
  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

参考情報

5
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
5
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?