Rails 3.1.0迁移中remove_index的正确语法是什么?

时间:2012-01-27 02:47:53

标签: ruby-on-rails ruby-on-rails-3.1 rails-migrations

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

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

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

令我失望的命令是:

bundle exec rake db:rollback STEP=1

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

6 个答案:

答案 0 :(得分:154)

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

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

所以在你的情况下

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

答案 1 :(得分:58)

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

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

答案 2 :(得分:44)

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

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

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

答案 3 :(得分:5)

我想扩展@ iWasRobbed的答案。如果你只对单个列有索引,那么担心remove_index就没有意义了(因为这只是一个假设!),数据库应该足够聪明,以清理该索引使用的资源。但是如果你有多列索引删除列将减少索引到仍然存在的列,这是完全明智的事情,但显示你可能想要明确使用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正确地将DB返回到先前的状态

答案 4 :(得分:0)

要更改表和/或其变量,请在迁移的#change操作中使用#change_table。然后,您可以按如下方式创建可逆索引删除:

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

如果您必须删除包含可逆操作的索引的表格,您可以使用SchemaStatements Table方法ConnectionAdapter def change drop_table :users do |t| t.index :email, :unique => true t.index :reset_password_token, :unique => true end end #up/down {1}}:

Table

如果您在迁移中完全需要ConnectionAdapter对。仅使用#drop_table方法以及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 类的Rails方法2.1.0

#import "RootTableViewController.h"

@interface RootTableViewController ()
@property (strong, nonatomic) IBOutlet UIStackView *stackView;

@property (strong, nonatomic) IBOutlet UIDatePicker *datePicker;
@end

@implementation RootTableViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // tableView automatic dimension
    self.tableView.estimatedRowHeight = 44;
    self.tableView.rowHeight = UITableViewAutomaticDimension;

   }

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    return 4;
}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];

    if (indexPath.row == 2) {
       UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"pickerCell" forIndexPath:indexPath];


        [_stackView addArrangedSubview:_datePicker];
        _stackView.translatesAutoresizingMaskIntoConstraints = NO;
        [cell.contentView addSubview:_stackView];


        NSLayoutConstraint *width =[NSLayoutConstraint
                                    constraintWithItem:_stackView
                                    attribute:NSLayoutAttributeWidth
                                    relatedBy:0
                                    toItem:cell.contentView
                                    attribute:NSLayoutAttributeWidth
                                    multiplier:1.0
                                    constant:0];
        NSLayoutConstraint *height =[NSLayoutConstraint
                                     constraintWithItem:_stackView
                                     attribute:NSLayoutAttributeHeight
                                     relatedBy:0
                                     toItem:cell.contentView
                                     attribute:NSLayoutAttributeHeight
                                     multiplier:1.0
                                     constant:0];
        NSLayoutConstraint *top = [NSLayoutConstraint
                                   constraintWithItem:_stackView
                                   attribute:NSLayoutAttributeTop
                                   relatedBy:NSLayoutRelationEqual
                                   toItem:cell.contentView
                                   attribute:NSLayoutAttributeTop
                                   multiplier:1.0f
                                   constant:0.f];
        NSLayoutConstraint *leading = [NSLayoutConstraint
                                       constraintWithItem:_stackView
                                       attribute:NSLayoutAttributeLeading
                                       relatedBy:NSLayoutRelationEqual
                                       toItem:cell.contentView
                                       attribute:NSLayoutAttributeLeading
                                       multiplier:1.0f
                                       constant:0.f];
       [cell.contentView addConstraints:@[width, height, top, leading]];

        [cell setNeedsLayout];
        [cell layoutIfNeeded];
        return cell;

    }
    cell.textLabel.text = @"Cell";

    return cell;
}

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{


    [_stackView removeArrangedSubview:_datePicker];
    [_datePicker removeFromSuperview];

}

@end

所有方法均可在{{1}}版本{{1}}或早期版本中使用。

答案 5 :(得分:0)

这是我的完整运行(在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) ==================