如何使列唯一并在Ruby on Rails迁移中建立索引?


416

我想unique在Ruby on Rails迁移脚本中创建一列。最好的方法是什么?还有没有一种方法可以索引表中的列?

我想unique在数据库中强制使用列,而不是仅使用:validate_uniqueness_of

Answers:


686

旧版Rails的简短答案(请参见Rails 4+的其他答案):

add_index :table_name, :column_name, unique: true

要将多个列一起建立索引,您可以传递一个列名数组,而不是单个列名,

add_index :table_name, [:column_name_a, :column_name_b], unique: true

如果收到“索引名称...太长”,则可以添加name: "whatever"到add_index方法中以使名称更短。

对于细粒度的控制,有一个“ execute”方法可以执行直接的SQL。

而已!

如果要代替常规的旧模型验证来执行此操作,请检查其工作原理。如果没有模型级别的验证,向用户报告错误的情况可能会不太好。两者都可以。


36
+1表示建议继续使用validates_uniqueness_of。使用这种方法来处理单个索引查询的代价,错误处理要干净得多,我建议他同时使用这两种方法
Steve Weet 09年

1
我尝试过似乎不起作用!我可以插入两个我定义为唯一的column_name的记录!我正在使用Rails 2.3.4和MySql有什么想法吗?

我通过执行使用了第二个建议:执行“ ALTER TABLE用户ADD UNIQUE(email)”,它起作用了!不知道为什么第一个对知道不感兴趣的人
Tam

1
如果indexed columns are not unique在尝试创建唯一索引时遇到错误,则可能是因为表中的数据已经包含重复项。尝试删除重复的数据,然后再次运行迁移。
哈特利·布罗迪

5
如果收到“索引名称...太长”,则可以添加, :name => "whatever"add_index方法中以使名称更短。
里克·史密斯

129

Rails生成迁移add_index_to_table_name column_name:uniq

要么

Rails生成迁移add_column_name_to_table_name column_name:string:uniq:index

产生

class AddIndexToModerators < ActiveRecord::Migration
  def change
    add_column :moderators, :username, :string
    add_index :moderators, :username, unique: true
  end
end

如果要向现有列添加索引,请删除或注释该add_column行,或进行检查

add_column :moderators, :username, :string unless column_exists? :moderators, :username

5
我赞成这一点,因为我想要命令行形式。但是即使我add_index...没有指定也添加列,这是很愚蠢的add_column...
Tyler Collier 2014年

1
是的,也许在下一版本中。
d.danailov 2014年

49

由于这尚未提及,但回答我时,我找到了这个网页的问题,你也可以指定通过加时,它的指数应该是唯一的t.referencest.belongs_to

create_table :accounts do |t|
  t.references :user, index: { unique: true } # or t.belongs_to

  # other columns...
end

(至少从Rails开始4.2.7


42

如果要创建新表,则可以使用内联快捷方式:

  def change
    create_table :posts do |t|
      t.string :title, null: false, index: { unique: true }
      t.timestamps
    end
  end

14

我正在使用Rails 5,上面的答案很好用;这是对我也有用的另一种方法(表名是:people,列名是:email_address

class AddIndexToEmailAddress < ActiveRecord::Migration[5.0]
  def change
    change_table :people do |t|
      t.index :email_address, unique: true
    end
  end
end


1
add_index :table_name, :column_name, unique: true

要将多个列索引在一起,请传递一个列名数组,而不是一个列名。


0

如果您错过了向数据库添加唯一列,只需在模型中添加此验证即可检查该字段是否唯一:

class Person < ActiveRecord::Base
  validates_uniqueness_of :user_name
end

请参阅此处 上面仅用于测试目的,请按照@Nate的建议通过更改数据库列来添加索引

请参考索引以获取更多信息


2
我不建议只添加没有相应索引的验证。更好的选择是清除所有现有重复项,然后添加索引。否则,您将冒使现有数据无效的风险(这将导致对这些行的任何更新失败),并且如果您有任何代码会跳过Rails验证,那么您仍然可能会重复。(例如,运行update_all或直接执行SQL插入时)
Nate
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.