Ruby-on-rails Rails 3.1.0 迁移中 remove_index 的正确语法是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9028387/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 02:42:27  来源:igfitidea点击:

What's the correct syntax for remove_index in a Rails 3.1.0 migration?

ruby-on-railsruby-on-rails-3.1rails-migrations

提问by doublea

I'm in the process of adding Devise to an existing Rails app, with a Users table already defined. The devise generator pushed out the following migration:

我正在将 Devise 添加到现有的 Rails 应用程序中,并且已经定义了一个用户表。设计生成器推出了以下迁移:

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

The downward migration isn't generated, and I'm having a heck of a time removing those indexes. I'm seeing different suggested notation in the documentation, and different suggestions online, but none of them seem to be working for me. For example...

不会生成向下迁移,而且我正在删除这些索引。我在文档中看到不同的建议符号,以及不同的在线建议,但似乎没有一个对我有用。例如...

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

results in...

结果是...

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

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

which is odd, because if I check the database, sure enough, 'index_users_on_email' is right there...

这很奇怪,因为如果我检查数据库,果然,'index_users_on_email' 就在那里......

I've tried other variations, including

我尝试了其他变体,包括

remove_index :users, :column => :email

remove_index :users, 'email'

or:

或者:

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

...but no dice. I'm running Rails 3.1.0, Ruby 1.9.2, rake 0.9.2.2, with Postgres.

...但没有骰子。我正在使用 Postgres 运行 Rails 3.1.0、Ruby 1.9.2、rake 0.9.2.2。

The command that's letting me down is:

让我失望的命令是:

bundle exec rake db:rollback STEP=1

after successfully apply the migration up. Any advice?

成功应用迁移后。有什么建议吗?

采纳答案by iwasrobbed

Depending on the database type, you don't need to worry about removing the indexes in the self.downmethod since the index will automatically be removed from the database when you drop the column.

根据数据库类型,您无需担心删除self.down方法中的索引,因为删除列时索引会自动从数据库中删除。

You can also use this syntax in your self.downmethod:

您还可以在您的self.down方法中使用此语法:

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

回答by Dty

For the record, the way to remove an index by name is

对于记录,按名称删除索引的方法是

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

so in your case

所以在你的情况下

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

回答by Maragues

You can also remove the index specifying the columns, which from my point of view is less error prone than writing the name

您还可以删除指定列的索引,从我的角度来看,这比编写名称更不容易出错

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

回答by dolzenko

I'd like to expand on @iWasRobbed's answer. If you have index on just single column then worrying about remove_indexdoesn't make sense since (just an assumtion!) the DB should be smart enough to cleanup the resources used by that index. But in case you have multiple columns index removing the column will reduce index to still existing columns, which is totally sensible thing to do, but kind of shows where you might want to use remove_indexexplicitely.

我想扩展@iWasRobbed 的回答。如果您只在单列上有索引,那么担心remove_index没有意义,因为(只是一个假设!)数据库应该足够聪明,可以清理该索引使用的资源。但是,如果您有多个列索引,删除该列会将索引减少到仍然存在的列,这是完全明智的做法,但会显示您可能想要remove_index明确使用的位置。

Just for illustration - migration below has that flaw that after being applied up and down it will leave the unique index on email(meaning the downpart is not doing its job properly)

只是为了说明 - 下面的迁移有一个缺陷,在上下应用后,它会留下唯一索引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

Changing the downblock to

down块更改为

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

will fix that flaw and allow the migration to correctly return DB to the previous state with rake db:rollback

将修复该缺陷并允许迁移正确地将数据库返回到先前的状态 rake db:rollback

回答by Малъ Скрылевъ

To alter a table and/or its indeces use #change_tableinside #changeaction of a migration. Then you be able to create reversable index removal as follows:

要更改表和/或其索引,请使用迁移的#change_table内部#change操作。然后您就可以创建可逆索引删除,如下所示:

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

When you have to drop a table with its index of course with reversable action you can use #drop_tablemethod for SchemaStatementswith the #indexmethod of Tableclass for ConnectionAdapter:

当您必须使用可逆操作删除带有其索引的表时,您可以使用#drop_table方法 forSchemaStatements和类的#index方法Tablefor ConnectionAdapter

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

In case you have need exactly the #up/downpair in a migration. Use just a #change_tablemethod along with #remove_indexmethod of Tableclass for ConnectionAdapter:

如果您#up/down在迁移中正好需要这对。只使用一个#change_table方法和类的#remove_index方法:TableConnectionAdapter

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

All of the methods are available in Railsversion of 2.1.0or of earlier ones.

所有方法都可以在早期Rails版本2.1.0或早期版本中使用。

回答by zee

Here is my full run of this(in Rails 5):

这是我的完整运行(在 Rails 5 中):

I have team_id as an index in table vendors. I no longer need this relation. To get rid of it. Did the following:

我有 team_id 作为表供应商的索引。我不再需要这种关系。摆脱它。做了以下事情:

1) create the migration.

1) 创建迁移。

  $ rails generate migration RemoveTeam_idFromVendor team_id:integer

2) Running the migration, give me this error. And that is because vendor table has rows whose foreign key references the primary key value of the team table

2)运行迁移,给我这个错误。那是因为 vendor 表中的行的外键引用了 team 表的主键值

== 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) To solve this and get the migration running, I did the following(Note: i am in dev):

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) ==================