Validando modelos aninhadas?
-
05-07-2019 - |
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.
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