Pregunta

Para ser más específico, " ¿Cómo validar que un modelo requiere que se creen al menos x modelos asociados válidos? " . He estado tratando de validar modelos anidados que se crean de la misma forma que los padres (y en última instancia, muestran validaciones inmediatas a la jQuery). Como ejemplo popular, asumamos los siguientes modelos y esquema.

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

Todas las validaciones se realizan en las definiciones de esquema, como puede ver. El importante aquí es " tiene 2..n,: tareas " ;. Esta validación en realidad funciona normalmente, dado que los atributos de la tarea anidada en el hash de parámetros producirán tareas válidas . Sin embargo, si producen una tarea inválida , entonces la tarea no se creará y terminará con un Proyecto que tiene menos de 2 tareas, y por lo tanto un no válido objeto del proyecto.

Tal como lo entiendo, esto se debe a que no puede averiguar si los atributos de la tarea son válidos o no hasta que intenta guardar las tareas, y desde , que yo sepa , las tareas no se pueden guardar antes del proyecto, el proyecto no sabe si las tareas serán válidas o no. ¿Estoy en lo correcto al asumir esto?

De todos modos, esperaba que hubiera una respuesta rápida, pero parece mucho menos trivial de lo que esperaba. Si tienes alguna sugerencia, sería muy apreciado.

¿Fue útil?

Solución

Realmente encontré una buena solución aquí usando transacciones en DataMapper. Básicamente, esta transacción intenta guardar el objeto principal, así como todos los objetos secundarios. Tan pronto como uno no puede guardar, la transacción se detiene y no se crea nada. Si todo va bien, entonces los objetos se guardarán con éxito.

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

Esto asegura que todo es válido antes de que se guarde algo. Solo necesitaba cambiar mis métodos #save y #update para #make en mi código de controlador.

Otros consejos

SET CONSTRAINTS DEFERRED podría ser útil si su motor de base de datos lo admite.

De lo contrario, tal vez escriba un procedimiento almacenado para hacer las inserciones, y luego diga que es la responsabilidad del procedimiento almacenado para asegurarse de que solo se inserten los datos correctos y validados.

Hay un método modelo ¿válido? que ejecuta las validaciones en un objeto modelo antes de guardarlo. Entonces, la forma simple de validar las asociaciones sería usar validates_with_block 'o' validates_with_method para verificar las validaciones en las asociaciones.

Se vería algo como esto

validates_with_block do
  if @tasks.all?{|t|t.valid?}
    true
  else
    [false, "you have an invalid task"]
  end
end

O puede mirar dm-association-validator o dm-accept-nested-atributos

Editar: para extra loco. ejecute las validaciones en las tareas, luego verifique si los únicos errores son los relacionados con la asociación.

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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top