Ich habe seit einigen Stunden zu kämpfen, um Validierungen verschachtelter Attribute in meiner Rails-App arbeiten zu lassen. Ein kleiner Vorbehalt ist, dass ich geschachtelte Attribute dynamisch basierend auf den Attributen ihrer Eltern validieren muss, da sich die Menge der benötigten Informationen im Laufe der Zeit ändert, je nachdem, wo sich der Elternteil befindet.Rails accepts_nested_attributes_for validation auf transactional Objekt
Also hier ist mein Setup: Ich habe ein Elternteil mit vielen verschiedenen verknüpften Modellen und ich möchte nachgeschachtelte Attribute dieser jedes Mal validieren, wenn ich das Elternteil speichern. In Anbetracht der Tatsache, dass Validierungen dynamisch ändern, ich hatte eine benutzerdefinierte Validierungsmethode in dem Modell zu schreiben:
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
In meinem Controller ich update_attributes an der Eltern rufen, wenn ich speichern möchten. Das Problem ist nun, dass rails anscheinend die Validierungen für die Datenbank ausführt und nicht für das Objekt, das vom Benutzer oder vom Controller geändert wurde. Was also passieren kann, ist, dass der Wert eines Kindes von einem Benutzer gelöscht wird und die Validierungen bestehen bleiben, während spätere Validierungen nicht bestanden werden, weil das Element in der Datenbank nicht gültig ist.
Hier ist ein kurzes Beispiel für dieses Szenario:
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
Die Validierung für First-Level-Verbände arbeitet, zum Beispiel Wenn ein Kind ein Attribut 'value' hat, könnte ich eine Validierung so durchführen, wie ich es tue. Das Problem liegt in tiefen Assoziationen, die vor dem Speichern offensichtlich nicht validiert werden können.
Kann mir jemand in die richtige Richtung zeigen, wie man das löst? Die einzige Möglichkeit, die ich derzeit sehe, ist das Speichern von Datensätzen, die anschließende Validierung und das Löschen/Zurücksetzen von Daten, wenn die Validierung fehlschlägt, aber ich hoffe ehrlich auf etwas Saubereres.
Vielen Dank im Voraus!
SOLUTION
So stellt sich heraus, dass ich durch Bezugnahme auf die direkt in der benutzerdefinierten Validierung, auf diese Weise Validierungen auf tief verschachtelten Modellen ausgeführt wird:
class Parent < ActiveRecord::Base
[...]
has_many :descriptions, :through => :children
[...]
def validate_nested_attributes
descriptions.each do |description|
[...]
end
end
end
die aus irgendeinem Grund führt zu den Problemen, Ich hatte oben. Danke Santosh, dass ich meinen Beispielcode getestet und berichtet habe, dass es funktioniert, das hat mich in die richtige Richtung gelenkt, um das herauszufinden.
Für zukünftige Referenz funktioniert der Code in der ursprünglichen Frage für diese Art von dynamischen, tief verschachtelten Validierungen.
Es gibt einige Fehler in Ihrem Code verwenden sollten. Es könnte Tippfehler sein. 1. "Kindwert kann nicht leer sein" - einzelnes Zitat innerhalb des einzelnen Anführungsstrichs. 2. && parent.status = 'validate_children' - Dies ist kein Vergleich. seine Zuordnung –
Entschuldigung wegen der Tippfehler! Der Code hier ist nur ein vereinfachtes Beispiel meiner App, so dass es nicht der Grund ist, warum es nicht funktioniert, aber danke, dass du das herausgebracht hast :) –