Ruby on rails 数据库唯一性约束不停止通过关联创建重复记录
我正在尝试向数据库中添加唯一性约束,以阻止向联接表中添加重复条目。然而,它似乎不起作用。我没有连接表的模型,因此我不添加模型级验证 以下是迁移:Ruby on rails 数据库唯一性约束不停止通过关联创建重复记录,ruby-on-rails,ruby,postgresql,ruby-on-rails-5,Ruby On Rails,Ruby,Postgresql,Ruby On Rails 5,我正在尝试向数据库中添加唯一性约束,以阻止向联接表中添加重复条目。然而,它似乎不起作用。我没有连接表的模型,因此我不添加模型级验证 以下是迁移: class CreateBreedsAndTags < ActiveRecord::Migration[5.1] def change create_table :breeds do |t| t.string :name, unique: true, present: true t.timestamps
class CreateBreedsAndTags < ActiveRecord::Migration[5.1]
def change
create_table :breeds do |t|
t.string :name, unique: true, present: true
t.timestamps
end
create_table :tags do |t|
t.string :name, unique: true, present: true
t.timestamps
end
create_join_table :breeds, :tags do |t|
t.integer :breed_id
t.integer :tag_id
t.index [:breed_id, :tag_id], unique: true
end
end
end
如果我在rails控制台中创建一个品种和标记。即使联接表上存在数据库级别的唯一约束,我也可以这样做:
b = Breed.create(name: 'b')
t = Tag.create(name: 't')
b << t
b << t
b.save!
b.tags # outputs the same tag multiple times
我运行了一个\d\u标签
Table "public.breeds_tags"
Column | Type | Modifiers
----------+--------+-----------
breed_id | bigint | not null
tag_id | bigint | not null
Indexes:
"index_breeds_tags_on_breed_id" btree (breed_id)
"index_breeds_tags_on_tag_id" btree (tag_id)
每次迁移最多只能创建或更改一个表。每次迁移都应该是对数据库的原子性和可逆性更改。如果在同一迁移中创建引用相同表和外键的表和外键,如果尝试将其反转,会发生什么情况
# rails g model tags name:string
class CreateTags < ActiveRecord::Migration[5.1]
def change
create_table :tags do |t|
t.string :name
t.timestamps
end
end
end
# rails g model breeds name:string
class CreateBreeds < ActiveRecord::Migration[5.1]
def change
create_table :breeds do |t|
t.string :name
t.timestamps
end
end
end
# rails g migration create_join_table_breeds_tags breeds tags
class CreateJoinTableBreedsTags < ActiveRecord::Migration[5.1]
def change
create_join_table :breeds, :tags do |t|
t.index [:breed_id, :tag_id], unique: true
end
end
end
事实上,您几乎不应该使用t.integer
进行关联。改用references宏
这将创建一个按预期工作的唯一性约束:
=> #<ActiveRecord::Associations::CollectionProxy [#<Tag id: 1, name: "bar", created_at: "2017-11-03 23:34:51", updated_at: "2017-11-03 23:34:51">]>
irb(main):005:0> b.tags << t
(0.2ms) BEGIN
SQL (3.8ms) INSERT INTO "breeds_tags" ("breed_id", "tag_id") VALUES ($1, $2) [["breed_id", 1], ["tag_id", 1]]
(0.2ms) ROLLBACK
ActiveRecord::RecordNotUnique: PG::UniqueViolation: ERROR: duplicate key value violates unique constraint "index_breeds_tags_on_breed_id_and_tag_id"
DETAIL: Key (breed_id, tag_id)=(1, 1) already exists.
每次迁移最多只能创建或更改一个表。每次迁移都应该是对数据库的原子性和可逆性更改。如果在同一迁移中创建引用相同表和外键的表和外键,如果尝试将其反转,会发生什么情况
# rails g model tags name:string
class CreateTags < ActiveRecord::Migration[5.1]
def change
create_table :tags do |t|
t.string :name
t.timestamps
end
end
end
# rails g model breeds name:string
class CreateBreeds < ActiveRecord::Migration[5.1]
def change
create_table :breeds do |t|
t.string :name
t.timestamps
end
end
end
# rails g migration create_join_table_breeds_tags breeds tags
class CreateJoinTableBreedsTags < ActiveRecord::Migration[5.1]
def change
create_join_table :breeds, :tags do |t|
t.index [:breed_id, :tag_id], unique: true
end
end
end
事实上,您几乎不应该使用t.integer
进行关联。改用references宏
这将创建一个按预期工作的唯一性约束:
=> #<ActiveRecord::Associations::CollectionProxy [#<Tag id: 1, name: "bar", created_at: "2017-11-03 23:34:51", updated_at: "2017-11-03 23:34:51">]>
irb(main):005:0> b.tags << t
(0.2ms) BEGIN
SQL (3.8ms) INSERT INTO "breeds_tags" ("breed_id", "tag_id") VALUES ($1, $2) [["breed_id", 1], ["tag_id", 1]]
(0.2ms) ROLLBACK
ActiveRecord::RecordNotUnique: PG::UniqueViolation: ERROR: duplicate key value violates unique constraint "index_breeds_tags_on_breed_id_and_tag_id"
DETAIL: Key (breed_id, tag_id)=(1, 1) already exists.
您是否通过
psql
查看了数据库中的连接表(即,没有所有ActiveRecord内容的影响)?@muistooshort i使用一些数据库信息更新了我的答案。看起来它创建了两个索引,但我没有看到唯一的约束?有als oa品种标签
表格!我基本上是从这个@Dbz运行查询的:你是对的。Rails创建了两个索引;它没有创建唯一的约束。“在保存对象之前验证属性的值是否唯一。它不会在数据库中创建唯一性约束…”@MikeSherrill'CatRecall'我实际使用的不是唯一性帮助器,而是数据库约束。我将创建一个连接模型,这样我也可以有一个唯一性助手。然而,我觉得奇怪的是,这个数据库约束不起作用。你没有你认为你有的数据库约束。你有没有通过psql
查看数据库中的连接表(即没有所有ActiveRecord内容)?@muistooshort我用一些数据库信息更新了我的答案。看起来它创建了两个索引,但我没有看到唯一的约束?有als oa品种标签
表格!我基本上是从这个@Dbz运行查询的:你是对的。Rails创建了两个索引;它没有创建唯一的约束。“在保存对象之前验证属性的值是否唯一。它不会在数据库中创建唯一性约束…”@MikeSherrill'CatRecall'我实际使用的不是唯一性帮助器,而是数据库约束。我将创建一个连接模型,这样我也可以有一个唯一性助手。但是,我觉得奇怪的是,这个db约束不起作用。你没有你认为有的数据库约束。这并不能确切地回答为什么你的代码会创建两个索引。但我无法复制这个问题,这在Rails 5应用程序中实际运行。嘿,max,谢谢你的回答。我同意使用引用
(并且不需要连接表),但我正在疯狂地测试任何东西!我会给你的建议一些想法和测试。再次感谢您这并不能确切回答为什么您的代码会创建两个索引。但我无法复制这个问题,这在Rails 5应用程序中实际运行。嘿,max,谢谢你的回答。我同意使用引用
(并且不需要连接表),但我正在疯狂地测试任何东西!我会给你的建议一些想法和测试。再次感谢你
=> #<ActiveRecord::Associations::CollectionProxy [#<Tag id: 1, name: "bar", created_at: "2017-11-03 23:34:51", updated_at: "2017-11-03 23:34:51">]>
irb(main):005:0> b.tags << t
(0.2ms) BEGIN
SQL (3.8ms) INSERT INTO "breeds_tags" ("breed_id", "tag_id") VALUES ($1, $2) [["breed_id", 1], ["tag_id", 1]]
(0.2ms) ROLLBACK
ActiveRecord::RecordNotUnique: PG::UniqueViolation: ERROR: duplicate key value violates unique constraint "index_breeds_tags_on_breed_id_and_tag_id"
DETAIL: Key (breed_id, tag_id)=(1, 1) already exists.
# rails g model breed_tag breed:belongs_to
# the table naming for has_many through: is different
class CreateBreedTags < ActiveRecord::Migration[5.1]
def change
create_table :breed_tags do |t|
t.belongs_to :breed, foreign_key: true
t.belongs_to :tag, foreign_key: true
t.index [:breed_id, :tag_id], unique: true
t.timestamps
end
end
end
class BreedTag < ApplicationRecord
belongs_to :breed
belongs_to :tag
validates_uniqueness_of :breed_id, scope: :tag_id
end
class Breed < ApplicationRecord
has_many :breed_tags
has_many :tags, through: :breed_tags
end
class Tag < ApplicationRecord
has_many :breed_tags
has_many :breeds, through: :breed_tags
end