A link
ma dwa components
: componenta_id
i componentb_id
. W tym celu w pliku Link
modelu mam:Sposób modelowania tego złożonego sprawdzania poprawności unikalności na połączonych polach
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 }
A w pliku migracji:
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
Pytanie: To wszystko działa. Teraz chcę, aby kombinacja componanta
i componentb
była unikalna, niezależnie od ich kolejności. Niezależnie od tego, który komponent to componenta
, a który z nich to componentb
(po tym wszystkim jest to samo łącze, połączenie między dwoma tymi samymi komponentami). Tak więc dwa poniższe zapisy nie powinny być dozwolone, ponieważ reprezentują to samo łącze, a zatem nie są unikalne:
- componenta_id = 1; componentb_id = 2
- componenta_id = 2; componentb_id = 1
Jak mogę utworzyć tę walidację niepowtarzalności? Mam sprawdzania poprawności modelu (patrz poniżej), ale zastanawiam się, czy i jak powinienem również dodać sprawdzania poprawności na poziomie migracji/db ...?
walidacji modelu
Mam walidacji modelu pracy z poniższym kodzie:
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
Poniższe badanie potwierdza powyższe prace:
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
Migracja/db sprawdzania poprawności:
Jako dodatkowy poziom bezpieczeństwa, czy istnieje również sposób na włączenie sprawdzania poprawności dla tego na poziomie db? W przeciwnym razie nadal można zapisać oba następujące rekordy do bazy danych: componenta_id = 1 ; componentb_id = 2
, a także componenta_id = 2 ; componentb_id = 1
.
W [rozmowa] (http://stackoverflow.com/questions/635937/how-do-i-specify-unique-constraint-for-multiple-columns-in-mysql) sugeruje się utworzenie relacji wiele do wielu: ' ma wiele elementów: " 'validates_length_of: components, maximum: 2' – skahlert