A link
имеет два components
: 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
Как я могу создать эту проверку уникальности? Я работаю над проверкой модели (см. Ниже), но задаю вопрос, следует ли и как добавить подтверждение на уровне миграции/db ...?
проверки модели
Я валидация модели работы с кодом ниже:
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
Migration/db validation:
Как дополнительный уровень безопасности, есть ли способ включить проверку для этого на уровне db? В противном случае все еще можно записать в базу данных две следующие записи: componenta_id = 1 ; componentb_id = 2
, а также componenta_id = 2 ; componentb_id = 1
.
В [этот разговор] (http://stackoverflow.com/questions/635937/how-do-i-specify-unique-constraint-for-multiple-columns-in-mysql) предложение состоит в том, чтобы создать отношение «многие ко многим»: ' имеет много компонентов: 'validates_length_of: компоненты, максимум: 2' – skahlert