2011-02-28 14 views
38

Tengo dos modelos.
- Parenthas_manyChildren;
- Parentaccept_nested_attributes_forChildren;Modelos anidados y validación principal

class Parent < ActiveRecord::Base 
    has_many :children, :dependent => :destroy 
    accepts_nested_attributes_for :children, :allow_destroy => true 
    validates :children, :presence => true 
end 

class Child < ActiveRecord::Base 
    belongs_to :parent 
end 

utilizo validación para validar la presencia de los niños para todos los padres, por lo que no se puede salvar padres sin hijos.

parent = Parent.new :name => "Jose" 
parent.save 
#=> false 
parent.children_attributes = [{:name => "Pedro"}, {:name => "Emmy"}] 
parent.save 
#=> true 

trabajos de validación. A continuación, vamos a destruir los niños a través de _destroy atributo:

parent.children_attributes = {"0" => {:id => 0, :_destroy => true}} 
parent.save 
#=> true !!! 
parent.reload.children 
#=> [] 

por lo que puede destruir todos los niños a través de formularios anidados y validación pasará.

En realidad esto sucede porque después borro niño de mis padres a través de _delete, el método de los niños sigue devolviendo destruido objeto antes de volver a cargarla, por lo que pasó la validación:

parent.children_attributes = {"0" => {:id => 0, :_destroy => true}} 
parent.save 
#=> true !!! 
parent.children 
#=> #<Child id:1 ...> # It's actually deleted 
parent.reload.children 
#=> [] 

Es error?

¿Cuál es la pregunta. La pregunta es la mejor solución para repararlo. Mi enfoque es agregar el filtro before_destroy al Child para verificar si es el último. Pero hace que el sistema sea complicado.

Respuesta

57

Esto probablemente funcione para usted, pero tengo la sensación de que hay una respuesta mucho mejor por ahí. Suena como un error para mí.

class Parent 
    validate :must_have_children 

    def must_have_children 
    if children.empty? or children.all? {|child| child.marked_for_destruction? } 
     errors.add(:base, 'Must have at least one child') 
    end 
    end 
end 
+0

sin embargo, es mejor que la validación de ':) gracias secundarios Child' – fl00r

+2

y gracias por' marked_for_destruction? ' – fl00r

+0

Este método de validación todavía se requiere como de rieles 3.0.6 – astjohn

0

No es un error. Según la documentación

Valida que los especificados atributos no están en blanco (como se define por objeto # blanco?)

y validates :children, :presence => true es sólo el mismo. La documentación no dice qué sucede si intenta usarlo en una asociación. Debe usar la validación personalizada usando validate.

Usando validates_presence_of en has_many asociación llama blank? en asociación children, que es un objeto de la clase Array. Como el blank? no está definido para Array, dispara method_missing que está atrapado dentro de Rails. Por lo general, hace lo que quiere pero me parece que falla en Rails 3.1rc y Ruby 1.8.7 de una manera realmente horrible: revierte silenciosamente los cambios de los registros asociados. Me tomó un par de horas descubrir qué está pasando.

+2

En realidad, el problema porque aumenta la presencia de niños ANTES de retirar a los niños.Entonces, ¿deberíamos verificar si los niños están 'marcado_para_destrucción?' – fl00r

Cuestiones relacionadas