Valider des modèles imbriqués?
-
05-07-2019 - |
Question
Pour être plus précis, "Comment puis-je valider qu'un modèle nécessite la création d'au moins x modèles associés valides?" . J'essaie de valider les modèles imbriqués créés sous la même forme que le parent (et affichent en fin de compte les validations immédiates à la jQuery). En tant qu’exemple courant, supposons les modèles et schémas suivants:
class Project
include DataMapper::Resource
property :id, Serial
property :title, String, :nullable => false
has 2..n, :tasks
end
class Task
include DataMapper::Resource
property :id, Serial
property :project_id, Integer, :key => true
property :title, String, :nullable => false
belongs_to :project
end
Toutes les validations sont effectuées dans les définitions de schéma, comme vous pouvez le voir. L’important ici est " a 2..n,: tâches
". Cette validation fonctionne normalement, étant donné que les attributs de tâches imbriqués dans le hachage params produiront des tâches valides . S'ils génèrent une tâche non valide , toutefois, la tâche ne sera pas créée et vous obtiendrez un projet comportant moins de 2 tâches, et donc un non valide objet du projet.
Quoi qu'il en soit, j'espérais une réponse rapide, mais cela semble beaucoup moins trivial que je ne l'avais espéré. Si vous avez des suggestions, nous vous en serions très reconnaissants.
La solution
En fait, j'ai trouvé une solution intéressante en utilisant des transactions dans DataMapper. Fondamentalement, cette transaction essaie de sauvegarder l’objet parent ainsi que tous les objets enfants. Dès que la sauvegarde échoue, la transaction s'arrête et rien n'est créé. Si tout se passe bien, les objets seront sauvegardés avec succès.
class Project
def make
transaction do |trans|
trans.rollback unless save
tasks.each do |task|
unless task.save
trans.rollback
break
end
end
end
end
end
Cela garantit que tout est valide avant que quelque chose soit sauvegardé. Je devais juste changer mes méthodes #save et #update pour #make dans le code de mon contrôleur.
Autres conseils
SET CONSTRAINTS DEFERRED peut être utile si votre moteur de base de données le prend en charge.
Sinon, écrivez peut-être une procédure stockée pour effectuer les insertions, puis dites que c’est la responsabilité de la procédure stockée de s’assurer que seules les données correctes et validées sont insérées.
Il existe une méthode de modèle valide?
qui exécute les validations sur un objet de modèle avant son enregistrement. Ainsi, le moyen simple de valider les associations serait d'utiliser validates_with_block 'ou' validates_with_method
pour vérifier les validations des associations.
Cela ressemblerait à quelque chose comme ça
validates_with_block do
if @tasks.all?{|t|t.valid?}
true
else
[false, "you have an invalid task"]
end
end
Vous pouvez également consulter dm-association-validator ou attributs dm-accepte-imbriqués
Modifier: pour un extra fou. exécutez des validations sur les tâches, puis vérifiez si les seules erreurs sont celles liées à l'association.
validates_with_block do
if @tasks.all?{|t|t.valid?;!t.errors.any?{|e|e[0]==:project}}
true
else
[false, "you have an invalid task"]
end
end