Wydawalo mi sie, ze jesli zaloze w tabeli odp. kolumne, a w modelu dam belongs_to by tej kolumny uzywalo to obiekt nie zostanie zapisany z wartoscia ID nieprawidlowa, tj. nie istniejaca w referowanej tabeli.
class User < ActiveRecord::Base
ma jakies pola
end
class Pony < ActiveRecord::Base
belongs_to :user
end
I zalozmy, ze mam tylko 1 rekord w tabeli A
Gdy normalnie zrobie b = Pony.create :user => User.find(1) wszystko zadziala pieknie i b.save sie powiedzie.
Ale myslalem, ze zrobienie b = Pony.create :user_id = 0xff wyrzuci blad bo nie ma w tabeli users takiego ID. Tymczasem b.save zapisze rekord do bazy.
A przeciez belongs_to :user tak naprawde dziala po kolumnie user_id…
class Pony < ActiveRecord::Base
belongs_to :user
validates_presence_of :user
end
do tego powinieneś jeszcze wymusić integralność po stronie bazy danych, czyli uczynić user_id kluczem obcym w tabeli users
Ogólnie developerzy railsów są strasznymi ignorantami jeśli chodzi o wymuszanie integralności bazy danych co ma odbicie w ActiveRecord. Żeby dodać klucz obcy musisz zawołać czystego SQLa przez #execute albo zainstalować plugina foreign_key_migrations http://github.com/harukizaemon/foreign_key_migrations/tree/master
Polecam to drugie rozwiązanie.
wystarczy, że w migracji zrobisz
t.integer :user_id, :null => false
…i klucz obcy do tabeli users zostanie dodany automatycznie
validates_presence_of - OK, ale co mu pomoże validates_associated? Sprawdzi tylko czy user jest sam w sobie przechodzi wszystkie walidacje. A zauważ, że w tym momencie klasa User nie ma żadnych walidacji
Dzięki za podpowiedzi; Tak mi się wydawało, że AR robi takie zgodności trochę “sobie a muzom”. Na razie używam SQlite’a, bo Rubyego trenuję dopiero tydzień
A jak to wygląda w DataMapperze (vide Merb?), który zdaje się z Railsami 3 ma zagościć?
Klucze obce podczas dewelopmenti i szczególnie testowania z fixturami mogą być problematyczne ( nie załaduje fixtur bo mu klucza brakuje ).
Dobrym rozwiązaniem jest założenie kluczy ale tylko na bazie produkcyjnej (plus ewentualnie deweloperskiej) ale pominięcie ich w testach z wykorzystaniem fixtur.
Nie wiem jak na mysql, ale w postgresie to nie jest problemem. Nie sprawdzałem dokładnie, ale podejrzewam, że podczas ładowania fixtur wyłączane jest sprawdzanie constraintów.
Nie zgodzę się, że to jest dobry pomysł. Załóżmy, że masz tabele users i groups. Tabela users ma klucz obcy group_id z ustawionym ON DELETE RESTRICT. Jeśli zrobić tak jak mówisz to w testach będziesz mógł usunąć grupę do której należą jacyś userzy, a w production już nie…