J'utilise accept_nested_attributes_for dans l'un de mes modèles Rails, et je veux enregistrer les enfants après avoir créé le parent.
Le formulaire fonctionne parfaitement, mais la validation échoue. Par souci de simplicité, imaginez ce qui suit:
class Project < ActiveRecord::Base
has_many :tasks
accepts_nested_attributes_for :tasks
end
class Task < ActiveRecord::Base
belongs_to :project
validates_presence_of :project_id
validates_associated :project
end
Et je cours:
Project.create!(
:name => 'Something',
:task_attributes => [ { :name => '123' }, { :name => '456' } ]
)
Lors de l'enregistrement du modèle de projet, la validation échoue sur les tâches car elles n'ont pas d'id_projet (puisque le projet n'a pas été enregistré).
Il semble que Rails suit le modèle ci-dessous:
Le modèle doit être:
Donc ma question se résume à: Comment puis-je obtenir Rails pour exécuter la méthode project_id = (ou project =) et la validation sur les enfants (tâches) APRÈS que le parent (projet) a été enregistré, mais PAS enregistrer le modèle parent (projet) si un enfant (tâche) n'est pas valide?
Des idées?
tilisez cette réponse pour Rails 2, sinon voir ci-dessous pour le :inverse_of
réponse
Vous pouvez contourner cela en pas en vérifiant le project_id si le projet associé est valide.
class Task < ActiveRecord::Base
belongs_to :project
validates_presence_of :project_id, :unless => lambda {|task| task.project.try(:valid?)}
validates_associated :project
end
Utilisation :inverse_of
et validates_presence_of :parent
. Cela devrait résoudre votre problème de validation.
class Dungeon < ActiveRecord::Base
has_many :traps, :inverse_of => :dungeon
end
class Trap < ActiveRecord::Base
belongs_to :dungeon, :inverse_of => :traps
validates_presence_of :dungeon
end
http://apidock.com/Rails/ActiveModel/Validations/HelperMethods/validates_presence_of
Validez uniquement la relation, pas l'ID:
class Task < ActiveRecord::Base
belongs_to :project
validates_presence_of :project
end
Dès que l'association est remplie, ActiveRecord considérera que la validation a réussi, que le modèle soit enregistré ou non. Vous pouvez également étudier la sauvegarde automatique pour vous assurer que le projet de la tâche est toujours enregistré:
class Task < ActiveRecord::Base
belongs_to :project, :autosave => true
validates_presence_of :project
end
Malheureusement, aucune des suggestions ci-dessus ne fonctionne pour moi avec Rails 2.3.5.
Dans mon cas, le projet dans une tâche est toujours nul si les deux sont créés à l'aide d'attributs imbriqués. Ce n'est que si je supprime validates_presence_of que la création se déroule correctement. Le test unitaire et le journal montrent que tout est créé correctement.
J'aurais donc tendance à ajouter des contraintes à la base de données au lieu de Rails car cela semble être plus fiable en premier lieu.
Vous pouvez simplement créer le projet et ajouter les projets uniquement s'il passe la validation:
tasks = params.delete(:task_attributes)
if Project.create(params)
Project.update_attributes(:task_attributes => tasks)
end
Ciao
Contrairement à ce que bigo suggère, il n'est pas toujours acceptable d'enregistrer d'abord l'objet parent puis les enfants. Habituellement, vous voulez vous assurer que tous les objets sont validés avant de commencer à les enregistrer. Cela donne à l'utilisateur la possibilité de rééditer le formulaire de saisie et de corriger les erreurs.
Le problème que vous décrivez sera résolu dans Rails 3.0. J'aurais publié un lien vers le ticket Lighthouse, mais stackoverflow.com ne le permet pas car je suis un nouvel utilisateur (#fail) Mais pour le moment, vous pouvez utiliser le plugin " parental_control ", qui corrigera votre "bug".