一个链接有两个组件:componenta_id
和componentb_id
。为此,在Link
模型文件中我有:
belongs_to :componenta, class_name: "Component"
belongs_to :componentb, class_name: "Component"
validates :componenta_id, presence: true
validates :componentb_id, presence: true
validates :componenta_id, uniqueness: { scope: :componentb_id }
validates :componentb_id, uniqueness: { scope: :componenta_id }
在迁移文件中:
create_table :links do |t|
t.integer :componenta_id, null: false
t.integer :componentb_id, null: false
...
end
add_index :links, :componenta_id
add_index :links, :componentb_id
add_index :links, [:componenta_id, :componentb_id], unique: true
问题:这一切都可以正常工作。现在我想让componanta
和componentb
的组合是唯一的,无论它们的顺序如何。所以无论哪个组件是componenta
,哪个组件是componentb
(毕竟这是同一个链接;两个相同组件之间的链接),这两个记录都不应该被允许,因为它们代表了相同的链接,因此不是唯一的:
- componenta_id = 1 ; componentb_id = 2
- componenta_id = 2 ; componentb_id = 1
我该如何创建这种唯一性验证?我已经使用以下代码实现了模型验证,但我想知道是否需要以及如何在迁移/数据库级别上添加验证…?
模型验证
我已经使用下面的代码实现了模型验证:
before_save :order_links
validates :componenta_id, uniqueness: { scope: :componentb_id }
private
def order_links
if componenta_id > componentb_id
compb = componentb_id
compa = componenta_id
self.componenta_id = compb
self.componentb_id = compa
end
end
以下测试确认了上述工作的有效性:
1. test "combination of two links should be unique" do
2. assert @link1.valid?
3. assert @link2.valid?
4. @link1.componenta_id = 3 #@link2 already has combination 3-4
5. @link1.componentb_id = 4
6. assert_not @link1.valid?
7. @link1.componenta_id = 4
8. @link1.componentb_id = 3
9. assert_raises ActiveRecord::RecordNotUnique do
10. @link1.save
11. end
12.end
迁移/数据库验证:
作为额外的安全级别,是否还有一种方法可以在数据库级别上进行验证?否则,仍然可以将以下两个记录都写入数据库:componenta_id = 1 ; componentb_id = 2
和 componenta_id = 2 ; componentb_id = 1
。
has many :components
validates_length_of :components,maximum:2
- skahlert