A link has two components : componenta_id and componentb_id . For this purpose, in the link model file, I have:
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 }
And in the migration file:
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
Question: It all works. Now I want the combination of componanta and componentb be unique, regardless of their order. Thus, no matter which componenta componenta , and which componentb (after all that is the same link, there is a connection between two identical components). Thus, the two entries below should not be allowed, as they represent the same link and therefore are not unique:
- componenta_id = 1; componentb_id = 2
- componenta_id = 2; componentb_id = 1
How can I create this uniqueness check? I am working on model validation (see below), but I ask the question, should and how to add confirmation at the migration level / db ...?
Model check
I have a model check that works with the code below:
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
The following test confirms the above work:
1. test "combination of two links should be unique" do 2. assert @link1.valid? 3. assert @link2.valid? 4. @link1.componenta_id = 3
Migration check / db:
As an added layer of security, is there a way to enable validation for this at db level? Otherwise, you can still write to the database the following two records: componenta_id = 1 ; componentb_id = 2 componenta_id = 1 ; componentb_id = 2 , as well as componenta_id = 2 ; componentb_id = 1 componenta_id = 2 ; componentb_id = 1 .