はじめに
Rails 6 に追加された新機能を試す第121段。 今回は、PostgreSQL index_exists?
編です。
Rails 6 (と Rails 5.2.4.1) では、 index_exists?
が正しく動作しないバグが fix されています。
Ruby 2.6.5, Rails 6.0.2.1, Rails 5.2.4.1, Rails 5.2.3, PostgreSQL 12.0 で確認しました。 (Rails 6.0.0 でこの修正が入っています。)
$ rails --version
Rails 6.0.2.1
今回は、 name の属性を持つ User モデルを作り、インデックスを追加して確認してみます。
Rails プロジェクトを作る
Rails プロジェクトを新たに作成します。
$ rails new rails_sandbox
$ cd rails_sandbox
User モデルを作る
name
属性を持つ User
モデルを作ります。
$ bin/rails g model User name
インデックスを追加する
今回は2つのインデックスを作成します。 lower(name)
を指定したインデックスと、単純に name
カラムを指定したインデックスです。
bin/rails g migration add_index_lower_name_to_users
class AddIndexLowerNameToUsers < ActiveRecord::Migration[6.0]
def change
add_index :users, 'lower(name)', name: 'index_lower_name'
add_index :users, 'name', name: 'index_name'
end
end
マイグレーションを実行する
マイグレーションを実行します。
bin/rails db:create db:migrate
rails console で確認する
rails c
を実行します。
$ bin/rails c
Running via Spring preloader in process 344
Loading development environment (Rails 6.0.2.1)
indexes
で登録されているインデックスを調べてみましょう。
(わかりやすいように表示は折り返してます。)
irb(main):001:0> User.connection.indexes(:users)
=> [
#<ActiveRecord::ConnectionAdapters::IndexDefinition:0x00005617bc6ef580
@table=:users,
@name="index_lower_name",
@unique=false,
@columns="lower((name)::text)", # <= ここに注目
@lengths={},
@orders={},
@opclasses={},
@where=nil,
@type=nil,
@using=:btree,
@comment=nil>,
#<ActiveRecord::ConnectionAdapters::IndexDefinition:0x00005617bc8c3be0
@table=:users,
@name="index_name",
@unique=false,
@columns=["name"], # <= ここに注目
@lengths={},
@orders={},
@opclasses={},
@where=nil,
@type=nil,
@using=:btree,
@comment=nil>
]
index_lower_name
に対応する @columns
が 'lower((name)::text)'
で String であるのに対して、 index_name
に対応する @columns
が ["name"]
とArray になっていることに注意してください。
index_exists?
を使って index_name
が存在することを確認します。
irb(main):002:0> User.connection.index_exists?(:users, "name", name: :index_name)
=> true
今度は、 index_lower_name
が存在することを確認します。
irb(main):003:0> User.connection.index_exists?(:users, "lower((name)::text)", name: :index_lower_name)
=> true
Rails 5 では
Rails 5.2.4.1 では、 Rails 6 と同じ動作ですが、 Rails 5.2.3 では、 index_lower_name
の存在を確認したとき false
を返します。
irb(main):001:0> User.connection.index_exists?(:users, "name", name: :index_name)
=> true
irb(main):002:0> User.connection.index_exists?(:users, "lower((name)::text)", name: :index_lower_name)
=> false
試したソース