2013-04-23 18 views
5

Mam problem od kilku godzin, aby sprawdzenie atrybutów zagnieżdżonych działało w mojej aplikacji rails. Małe zastrzeżenie polega na tym, że muszę sprawdzać atrybuty zagnieżdżone dynamicznie w oparciu o ich atrybuty rodzica, ponieważ ilość wymaganych informacji zmienia się w czasie w zależności od miejsca w procesie, w którym znajduje się rodzic.Rails accept_nested_attributes_for validation na obiekcie transakcyjnym

Oto moja konfiguracja: Mam obiekt nadrzędny z wieloma różnymi skojarzonymi modelami i chcę sprawdzać kolejno zagnieżdżone atrybuty tych za każdym razem, gdy zapisuję obiekt nadrzędny. Biorąc pod uwagę fakt, że walidacje zmieniają się dynamicznie, musiałem napisać metodę zwyczaj sprawdzania poprawności w modelu

class Parent < ActiveRecord::Base 
    attr_accessible :children_attributes, :status 
    has_many :children 
    accepts_nested_attributes_for :children 
    validate :validate_nested_attributes 
    def validate_nested_attributes 
    children.each do |child| 
     child.descriptions.each do |description| 
     errors.add(:base, "Child description value cant be blank") if description.value.blank? && parent.status == 'validate_children' 
     end 
    end 
    end 
end 


class Child < ActiveRecord::Base 
    attr_accessible :descriptions_attributes, :status 
    has_many :descriptions 
    belongs_to :parent 
    accepts_nested_attributes_for :descriptions 
end 

W moim kontroler nazywam update_attributes na rodzica, gdy chcę, aby zapisać. Problem polega na tym, że prawdopodobnie szyny przeprowadzają walidacje w bazie danych, a nie w stosunku do obiektu, który został zmodyfikowany przez użytkownika lub kontroler. Więc może się zdarzyć, że wartość użytkownika zostanie usunięta przez użytkownika, a sprawdzanie poprawności zostanie zakończone, a późniejsze sprawdzanie poprawności nie przejdzie, ponieważ element w bazie danych jest niepoprawny.

Oto krótki przykład tego scenariusza:

parent = Parent.create({:status => 'validate_children', :children_attributes => {0 => {:descriptions_attributes => { 0 => {:value => 'Not blank!'}}}}) 
    #true 
parent.update_attributes({:children_attributes => {0 => {:descriptions_attributes => { 0 => {:value => nil}}}}) 
    #true!!/since child.value.blank? reads the database and returns false 
parent.update_attributes({:children_attributes => {0 => {:descriptions_attributes => { 0 => {:value => 'Not blank!'}}}}) 
    #false, same reason as above 

Walidacja pracuje dla organizacji pierwszego stopnia, na przykład jeśli dziecko ma atrybut "value", mogę przeprowadzić walidację w taki sam sposób jak ja. Problem polega na głębokich skojarzeniach, które najwyraźniej nie mogą być zatwierdzone przed zapisaniem.

Czy ktoś może wskazać mi właściwy kierunek rozwiązania? Jedyny sposób, jaki widzę obecnie, to zapisywanie rekordów, ich walidacja i usuwanie/przywracanie, jeśli walidacja się nie powiedzie, ale szczerze mam nadzieję, że coś będzie czystsze.

Dziękuję wszystkim z góry!

ROZWIĄZANIE

Okazuje się, biegałam walidacji na głębokich modeli zagnieżdżonych poprzez odniesienie tych bezpośrednio w walidacji niestandardowej, w ten sposób:

class Parent < ActiveRecord::Base 
    [...] 
    has_many :descriptions, :through => :children 
    [...] 
    def validate_nested_attributes 
    descriptions.each do |description| 
     [...] 
    end 
    end 
end 

które z jakiegoś powodu prowadzi do problemów Miałem powyżej. Dzięki Santoshowi za przetestowanie mojego przykładu kodu i zgłoszenie, że działa, to wskazało mi właściwy kierunek, aby to zrozumieć.

W celu późniejszego wykorzystania, kod w pytaniu oryginalnym działa w przypadku tego typu dynamicznych, głęboko zagnieżdżonych sprawdzeń.

+0

Istnieje kilka błędów w kodzie. To może być literówka. 1. "Wartość podrzędna nie może być pusta" - pojedynczy cudzysłów w jednym cudzysłowie. 2. && parent.status = 'validate_children' - To nie jest porównanie. jego zadanie –

+0

przykro mi z powodu literówek! Kod tutaj jest tylko uproszczonym przykładem mojej aplikacji, więc nie jest to powód, dla którego nie działa, ale dzięki za wskazanie tego :) –

Odpowiedz

2

myślę, że należy użyć validates_associated tego

z następującym walidacji u dziecka

validates :value, :presence => true, :if => "self.parent.status == 'validate_children'" 
+0

Witaj Santhoshie, dzięki za szybką odpowiedź! Już weszłam na stronę validates_associated, ale ogólne odczucie jest takie, że jest to bardziej kłopotliwe niż cokolwiek innego. Czy istnieje sposób sprawdzania poprawności skojarzonych atrybutów rekordów tylko z modelem rodzica bez dotykania własnego modelu?Byłoby to konieczne, ponieważ w mojej konfiguracji dziecko może mieszkać w bazie danych bez wartości, ale tylko wtedy, gdy status rodzica jest inny niż "validate_children". –

+0

W takim przypadku możesz dodać sprawdzanie poprawności w dzieciach takich jak to: validates: value,: presence => true,: if => "self.parent.status == 'validate_children'" –

+0

Hej Santhosh, jeszcze raz dziękuję za odpowiedź. Problem polega na tym, że moja aplikacja jest nieco bardziej skomplikowana niż w przykładzie i obejmuje również stowarzyszenia polimorficzne, dlatego znacznie lepiej byłoby zachować walidację na poziomie nadrzędnym. Właśnie zorientowałem się w pracy sprawdzania poprawności na modelach zagnieżdżonych pierwszego poziomu, ale nie mają one zastosowania w zagnieżdżonych. Na przykład. jeśli dzieci mają opisy, walidacja zadziała dla dzieci, ale nie dla ich opisów. –