ruby-on-rails 向列组合添加唯一约束的迁移

vddsk6oq  于 2023-02-26  发布在  Ruby
关注(0)|答案(7)|浏览(121)

我需要的是一个迁移,以应用唯一约束到列的组合。即对于people表,first_namelast_NameDob的组合应该是唯一的。

jaxagkaj

jaxagkaj1#

add_index :people, [:firstname, :lastname, :dob], unique: true

bjg7j2ky

bjg7j2ky2#

根据howmanyofme.com的数据,仅在美国就有“46,427个叫约翰·史密斯的人”。这大约是127年的天数。由于这远远超过了人类的平均寿命,这意味着出生日期冲突在数学上是肯定的。
我想说的是,这种独特字段的特定组合可能会在未来导致用户/客户极度沮丧。
考虑一些实际上是唯一的东西,如国家身份证号码,如果合适的话。
(我意识到我写这篇文章已经很晚了,但它可能会对未来的读者有所帮助。)

ddrv8njm

ddrv8njm3#

您可能希望添加一个没有索引的约束。这将取决于您使用的数据库。以下是Postgres的示例迁移代码。(tracking_number, carrier)是您希望用于约束的列的列表。

class AddUniqeConstraintToShipments < ActiveRecord::Migration
  def up
    execute <<-SQL
      alter table shipments
        add constraint shipment_tracking_number unique (tracking_number, carrier);
    SQL
  end

  def down
    execute <<-SQL
      alter table shipments
        drop constraint if exists shipment_tracking_number;
    SQL
  end
end

您可以添加不同的约束。阅读文档

dgsult0t

dgsult0t4#

为了完整起见,也为了避免混淆,这里有3种方法可以做同样的事情:

    • 在Rails 5.2+中向列组合添加命名的唯一约束**

假设我们有一个属于某个广告客户的Locations表,该表具有列reference_code,而您只希望每个广告客户有一个引用代码,因此您希望为列组合添加一个唯一约束并对其命名。
执行:
rails g migration AddUniquenessConstraintToLocations
让您的迁移看起来像这样一行代码:

class AddUniquenessConstraintToLocations < ActiveRecord::Migration[5.2]
  def change
    add_index :locations, [:reference_code, :advertiser_id], unique: true, name: 'uniq_reference_code_per_advertiser'
  end
end

或此块版本。

class AddUniquenessConstraintToLocations < ActiveRecord::Migration[5.2]
  def change
    change_table :locations do |t|
     t.index ['reference_code', 'advertiser_id'], name: 'uniq_reference_code_per_advertiser', unique: true
    end
  end
end

或此原始SQL版本

class AddUniquenessConstraintToLocations < ActiveRecord::Migration[5.2]
  def change
      execute <<-SQL
          ALTER TABLE locations
            ADD CONSTRAINT uniq_reference_code_per_advertiser UNIQUE (reference_code, advertiser_id);
        SQL
  end
end

其中任何一个都将具有相同的结果,请检查您的schema.rb

50pmv0ei

50pmv0ei5#

例如,您可以在迁移中为列添加唯一索引

add_index(:accounts, [:branch_id, :party_id], :unique => true)

或为每列单独创建唯一索引

wfsdck30

wfsdck306#

在用户和帖子之间的连接表的典型示例中:

create_table :users
create_table :posts

create_table :ownerships do |t|
  t.belongs_to :user, foreign_key: true, null: false
  t.belongs_to :post, foreign_key: true, null: false
end

add_index :ownerships, [:user_id, :post_id], unique: true

尝试创建两个相似的记录会抛出一个数据库错误(在我的例子中是Postgres):

ActiveRecord::RecordNotUnique: PG::UniqueViolation: ERROR:  duplicate key value violates unique constraint "index_ownerships_on_user_id_and_post_id"
DETAIL:  Key (user_id, post_id)=(1, 1) already exists.
: INSERT INTO "ownerships" ("user_id", "post_id") VALUES ($1, $2) RETURNING "id"

例如:

Ownership.create!(user_id: user_id, post_id: post_id)
Ownership.create!(user_id: user_id, post_id: post_id)

完全可运行的示例:https://gist.github.com/Dorian/9d641ca78dad8eb64736173614d97ced
生成的db/schema.rbhttps://gist.github.com/Dorian/a8449287fa62b88463f48da986c1744a

tquggr8v

tquggr8v7#

如果您正在创建一个新表,只需添加unique:真

class CreatePosts < ActiveRecord::Migration[6.0]
  def change
    create_table :posts do |t|
      t.string :title, unique: true
      t.text :body
      t.references :user, foreign_key: true
      t.timestamps
    end

    add_index :posts, :user_id, unique: true
  end
end

相关问题