Pergunta

Para ser mais específico, "Como posso validar que um modelo requer pelo menos x modelos associados válidos sendo criados?" . Eu tenho tentado para validar modelos aninhados que são criadas da mesma forma como o pai (e, finalmente, mostrar validações imediatos a la jQuery). Como um exemplo popular, vamos supor os seguintes modelos e 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 as validações são feitas nas definições de esquema, como você pode ver. O importante aqui é "has 2..n, :tasks". Esta validação realmente funciona normalmente, dado que atribui a tarefa aninhada no hash params irá produzir válidos tarefas. Se eles produzir um inválido tarefa, no entanto, a tarefa não vai ser criada e você vai acabar com um projeto que tem menos de 2 tarefas e, assim, um inválido objeto de projeto.

Pelo que entendi, isso é porque ele não consegue descobrir se os atributos da tarefa são válidos ou não até que ele tenta salvar as tarefas, e uma vez que - , tanto quanto eu sei - o tarefas não podem ser salvo antes do projeto, o projeto não tem conhecimento se as tarefas será válida ou não. Estou correto em assumir isso?

De qualquer forma, eu estava esperando que haveria uma resposta rápida, mas parece muito menos trivial então eu esperava. Se você tem alguma sugestão em tudo, que seria muito apreciado.

Foi útil?

Solução

Na verdade, eu encontrei uma boa solução aqui usando transações em DataMapper. Basicamente esta transação tenta salvar o objeto pai, bem como todos os objetos filho. Assim que uma falha para salvar, então a transação pára e nada é criado. Se tudo correr bem, em seguida, os objetos vai economizar com sucesso.

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

Isto assegura que tudo é válido antes de qualquer coisa é salvo. Eu só precisava mudar minha #save e métodos #update para #make no meu código controlador.

Outras dicas

SET CONSTRAINTS DIFERIDO pode ser útil se os suportes do motor de banco de dados que.

Caso contrário, talvez escrever um procedimento armazenado para fazer as inserções e, em seguida, dizer que a sua a resonsibility do procedimento armazenado para garantir é inserido que os dados só correto, validado.

Existe um método modelo valid? que executa as validações em um modelo de objeto antes de ser salvo. Assim, a simples forma de validar as associações seria usar validates_with_block' or 'validates_with_method para verificar as validações nas associações.

Seria algo parecido com isto

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

Ou você pode olhar para dm-associação-validador ou dm-aceita nested-atributos

Editar: para louco extra. executar validações sobre as tarefas, em seguida, verificar para ver se os únicos erros são aqueles relacionados com a associação.

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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top