我有一个具有HABTM自我加入关系的模型(Company
)(联接表调用关联公司suppliers
和purchasers
)。
我想阻止公司拥有重复的供应商或购买者,因此我在供应商 - 购买者对中添加了唯一性约束。我在数据库级别添加了这个约束:
create_table :supply_link, id: false do |t|
t.belongs_to :supplier, null: false, index: true
t.belongs_to :purchaser, null: false, index: true
end
add_index :supply_link, [:supplier_id, :purchaser_id], unique: true
和数据模型级别:
class Company < ApplicationRecord
has_and_belongs_to_many :purchasers, -> { distinct },
join_table: :supply_link,
class_name: :Company,
foreign_key: :supplier_id,
association_foreign_key: :purchaser_id
has_and_belongs_to_many :suppliers, -> { distinct },
join_table: :supply_link,
class_name: :Company,
foreign_key: :purchaser_id,
association_foreign_key: :supplier_id
end
但是在尝试为这种安排编写规范时,我注意到一些奇怪的事情:通常,数据模型验证优先于数据库约束 - 但不是在这里。
也就是说,如果同时设置数据模型验证(validates :email, presence: true
)和数据库约束(t.string :email, null: false
),则数据模型会捕获无效操作(如User.create(email: nil)
) DB甚至都看到了它们。
但是在这种情况下,当我尝试多次将supplier
添加到Company
时,它首先会转到数据库,并引发错误。如果我完全删除了数据库约束,那么数据模型以正确的方式处理它,并且重复的条目永远不会被添加到会发生两件事:1)重复的关联所有都显示在连接表中,但2)模型没有显示suppliers
属性。company.suppliers
的任何重复项(感谢@Pavel Mihailyuk)。我在控制台中手动测试了这个,并使用RSpec / FactoryGirl。
这里发生了什么,编写规范的正确方法是什么?我应该同时保留两个验证并期望无效操作引发ActiveRecord
错误吗?我应该删除数据库约束并仅依赖于数据模型的-> { distinct }
范围吗?我应该将此报告为Rails中的错误吗?