2010-10-25 9 views
4

J'utilise Rails 2.3.8 et accepte_nested_attributes_for.accepte_nested_attributes_for validation

J'ai un objet de catégorie simple qui utilise awesome_nested_set pour autoriser les catégories imbriquées.

Pour chaque catégorie je voudrais un champ unique appelé code. Ce serait unique pour la catégorie par niveau. Les catégories parentales auront tous des codes uniques et les sous-catégories seront uniques dans leur propre catégorie parentale.

EG:

code name 
1 cat1 
    1 sub cat 1 
2 cat2 
    1 sub cat 1 
    2 sub cat 2 
3 cat3 
    1 sub1 

Cela fonctionne sans le processus de validation, mais quand j'essaie d'utiliser quelque chose comme: validates_uniqueness_of: code,: scope =>: PARENT_ID

Cela ne fonctionnera pas parce que le parent n'a pas encore été enregistré.

Voici mon modèle:

class Category < ActiveRecord::Base 
    acts_as_nested_set 
    accepts_nested_attributes_for :children, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true 

    default_scope :order => "lft" 

    validates_presence_of :code, :name, :is_child 
    validates_uniqueness_of :code, :scope => :parent_id 
end 

J'ai pensé à une autre façon de le faire et il est très proche de travailler, problème est que je ne peux pas vérifier l'unicité entre les catégories d'enfants.

Dans ce second exemple, j'ai inséré un champ caché dans la forme appelée 'is_child' pour indiquer si l'élément est une sous-catégorie ou non. Voici mon exemple de ce modèle:

class Category < ActiveRecord::Base 
    acts_as_nested_set 
    accepts_nested_attributes_for :children, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true 

    default_scope :order => "lft" 

    validates_presence_of :code, :name, :is_child 
    #validates_uniqueness_of :code, :scope => :parent_id 
    validate :has_unique_code 

    attr_accessor :is_child 


    private 
    def has_unique_code 

    if self.is_child == "1" 
     # Check here if the code has already been taken this will only work for 
     # updating existing children. 
    else 

     # Check code relating to other parents 
     result = Category.find_by_code(self.code, :conditions => { :parent_id => nil}) 

     if result.nil? 
     true 
     else 
     errors.add("code", "Duplicate found") 
     false 
     end 
    end 
    end 
end 

Ceci est très proche. S'il y avait un moyen de détecter les codes en double dans la syntaxe reject_if sous accept_nested_attributes_for alors je serais là. Tout cela semble trop compliqué et aimerait des suggestions pour le rendre plus facile. Nous aimerions continuer à ajouter des catégories et des sous-catégories dans le même formulaire, car cela accélère la saisie des données.

Mise à jour: Peut-être devrais-je utiliser build ou before_save.

Répondre

4

Au lieu de

validates_uniqueness_of :code, :scope => :parent_id 

Essayez

validates_uniqueness_of :code, :scope => :parent 

En outre, vous aurez besoin de mettre dans la classe Catégorie:

has_many :children, :inverse_of => :category # or whatever name the relation is called in Child 

L'utilisation de inverse_of fera les enfants variables parent être défini avant l'enregistrement, et il y a une chance que cela fonctionne.

+0

Merci! J'ai essayé de valider un champ imbriqué en utilisant des valeurs de son objet parent dans le cadre de la validation. Il échouait sur de nouveaux objets car le parent n'était pas disponible. La: reverse_of declaration l'a fait fonctionner! –