2010-06-30 3 views
4

Comment puis-je valider qu'un modèle possède au moins un modèle associé utilisant des attributs imbriqués? Cela m'a rendu fou car je suis sûr qu'il me manque quelque chose de simple. Par exemple, je veux exiger qu'une liste ait toujours au moins une tâche.Valider la présence d'attributs imbriqués

class List < ActiveRecord::Base 
    has_many :tasks, :dependent => :destroy 
    accepts_nested_attributes_for :tasks, :allow_destroy => true 
end 

class Task < ActiveRecord::Base 
    belongs_to :list 
end 

J'ai essayé beaucoup d'options différentes.

1- ajouter une validation des listes:

def validate 
    if self.tasks.length < 1 
    self.errors[:base] << "A list must have at least one task." 
    end 
end 

mais cela vous permettra toujours de supprimer toutes les tâches d'un existant liste depuis lors de la suppression des tâches de la validation de la liste des tâches qui se passe avant sont détruits .

2- vérifier si les tâches ne sont pas marqués pour la destruction dans un rappel before_save

before_save :check_tasks 

private 
#look for any task which won't be deleted 
def check_tasks 
    for t in self.tasks 
    return true if ! t.marked_for_destruction? 
    end 
    false 
end 

Pour une raison quelconque, je ne peux pas le faire pour supprimer jamais une tâche avec tout ce qui parcourt les tâches d'une liste . La même chose est vraie si je fais ce chèque en def validate au lieu d'un rappel

3- nécessitant la présence de tâches validates_presence_of :tasks, mais avec cela, il ne sera jamais supprimer toutes les tâches

Répondre

3

J'ai fini par étendre la méthode de sauvegarde du magazine pour contourner le problème. Ça a marché comme sur des roulettes.

def save 
    saved = false 
    ActiveRecord::Base.transaction do 
    saved = super 
    if self.conditions.size < 1 
     saved = false 
     errors[:base] << "A rule must have at least one condition." 
     raise ActiveRecord::Rollback 
    end 
    end 
    saved 
end 
+0

C'est très utile, merci! –

7

Vous pouvez vérifier les conditions ensemble méthode de validation:

validate :check_tasks 
    def check_tasks 
    if self.tasks.size < 1 || self.tasks.all?{|task| task.marked_for_destruction? } 
     errors.add_to_base("A list must have at least one task.") 
    end 
    end 
+0

J'aime votre style, et je suis d'accord ce qui devrait fonctionner (j'ai essayé quelque chose de très similaire dans mes tests), mais chaque fois que vous itérer sur les tâches de l'objet de la liste dans le modèle, aucune des tâches sera supprimé J'ai essayé cela avec 2.3.8 et 3.0.0beta4 en vain –

+0

Il est étrange, j'ai testé avec Rails 2.3.8, et cela fonctionne. Une chose: les enregistrements sont supprimés de la base de données, mais pas supprimés de la collection en cache 'list.tasks'. Il peut donc sembler que les tâches n'ont pas été supprimées. Vous pouvez essayer 'list.tasks.reload' si vous avez besoin d'accéder à votre objet après la mise à jour. – Voyta

Questions connexes