web-dev-qa-db-ja.com

Rails 3.1.0移行のremove_indexの正しい構文は何ですか?

私はDeviseを既存のRailsアプリに既に追加しています。Usersテーブルは既に定義されています。deviseジェネレーターは次の移行を推進しました。

class AddDeviseToUsers < ActiveRecord::Migration
  def self.up
    change_table(:users) do |t|

     ## Database authenticatable
     t.string :email,              :null => false, :default => ""
     t.string :encrypted_password, :null => false, :default => ""

     ## Recoverable
     t.string   :reset_password_token
     t.datetime :reset_password_sent_at

     ## Rememberable
     t.datetime :remember_created_at

     ## Trackable
     t.integer  :sign_in_count, :default => 0

     blah blah blah....

   end

   add_index :users, :email,                :unique => true
   add_index :users, :reset_password_token, :unique => true
 end

下方移行は生成されず、これらのインデックスを削除するのに時間がかかります。ドキュメントにはさまざまな表記法が提案されており、オンラインではさまざまな提案が見られますが、それらのどれも私には役に立たないようです。例えば...

def self.down
  change_table(:users) do |t|
    t.remove  :email
    t.remove  :encrypted_password

    t.remove  :reset_password_token

    blah blah blah...
  end

  remove_index :users, :email
  remove_index :users, :reset_password_token
end

結果は...

An error has occurred, this and all later migrations canceled:

Index name 'index_users_on_email' on table 'users' does not exist

データベースをチェックすると、「index_users_on_email」がすぐそこにあるので、これは奇妙です...

他のバリエーションを試しました

remove_index :users, :column => :email

remove_index :users, 'email'

または:

change_table(:users) do |t|
  t.remove_index :email
end

...しかしサイコロはありません。私はRails 3.1.0、Ruby 1.9.2、rake 0.9.2.2、Postgresで実行しています。

私を失望させているコマンドは次のとおりです。

bundle exec rake db:rollback STEP=1

移行を正常に適用した後。何かアドバイス?

64
doublea

データベースの種類によっては、self.downメソッドでインデックスを削除することを心配する必要はありません。列を削除するとインデックスがデータベースから自動的に削除されるためです。

self.downメソッドで次の構文を使用することもできます。

def self.down
   remove_column :users, :email
   remove_column :users, :encrypted_password
   remove_column :users, :reset_password_token
end
44
iwasrobbed

レコードの場合、名前でインデックスを削除する方法は

remove_index(:table_name, :name => 'index_name')

あなたの場合

remove_index(:users, :name => 'index_users_on_email')
154
Dty

また、列を指定するインデックスを削除することもできます。これは、私の観点からは、名前を書くよりもエラーが少ないです。

remove_index :actions, :column => [:user_id, :action_name]
58
Maragues

@iWasRobbedの答えを詳しく説明したいと思います。単一の列のみにインデックスがある場合、remove_indexは(単なる仮定として!)DBがそのインデックスによって使用されるリソースをクリーンアップするのに十分スマートである必要があるため、意味がありません。ただし、複数の列のインデックスがある場合、列を削除するとインデックスがまだ存在する列に減少します。これは実行するのが賢明なことですが、remove_index明示的に。

説明のためだけに、以下の移行には、上下に適用された後、emailに一意のインデックスが残るという欠陥があります(つまり、down部分が適切に機能していないことを意味します)

class AddIndexes < ActiveRecord::Migration
  def up
    add_column :users, :action_name, :string
    add_index  :users, [:email, :action_name], unique: true
  end

  def down
    remove_column :users, :action_name
  end
end

downブロックを

  def down
    remove_index :users, [:email, :action_name]
    remove_column :users, :action_name
  end

この欠陥を修正し、rake db:rollback

5
dolzenko

これの私の完全な実行です(Rails 5):

テーブルベンダーのインデックスとしてteam_idがあります。この関係はもう必要ありません。それを取り除くために。以下を行いました:

1)移行を作成します。

  $ Rails generate migration RemoveTeam_idFromVendor team_id:integer

2)移行を実行すると、このエラーが発生します。それは、ベンダーテーブルには、外部キーがチームテーブルのプライマリキー値を参照する行があるためです。

== 20170727202815 RemoveTeamIdFromVendor: migrating ===========================
-- remove_column(:vendors, :team_id, :integer)
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:

SQLite3::ConstraintException: FOREIGN KEY constraint failed: DROP TABLE "vendors"

3)これを解決し、移行を実行するために、次のことを行いました(注:開発中です):

$ rake db:drop


Dropped database 'db/development.sqlite3'
Dropped database 'db/test.sqlite3'


$ rake db:create
Created database 'db/development.sqlite3'
Created database 'db/test.sqlite3'

$ rake db:migrate
~
~
~

== 20170727202815 RemoveTeamIdFromVendor: migrating ===========================
-- remove_column(:vendors, :team_id, :integer)
   -> 0.0185s
== 20170727202815 RemoveTeamIdFromVendor: migrated (0.0185s) ==================
0
zee

テーブルおよび/またはそのインデックスを変更するには、移行の#change_tableアクション内で #change を使用します。次に、次のように可逆インデックスの削除を作成できます。

def change
   change_table :users do |t|
      t.index :email, :unique => true
      t.index :reset_password_token, :unique => true
   end
end

もちろん、リバーシブルアクションを使用してインデックス付きのテーブルを削除する必要がある場合は、SchemaStatements#drop_table メソッドをTableConnectionAdapterクラスの #index メソッド:

def change
   drop_table :users do |t|
      t.index :email, :unique => true
      t.index :reset_password_token, :unique => true
   end
end

移行時に#up/downペアが正確に必要な場合。 #change_table メソッドとともに #remove_indexTableConnectionAdapterクラスのメソッド:

def up
   change_table :users do |t|
      t.index :email, :unique => true
      t.index :reset_password_token, :unique => true
   end
end

def down
   change_table :users do |t|
      t.remove_index :email, :unique => true
      t.remove_index :reset_password_token, :unique => true
   end
end

すべてのメソッドは、2.1.0またはそれ以前のRailsバージョンで使用できます。