Recentemente fazendo algumas refatorações de código, identifiquei um problema onde a validação de alguns changesets não estavam funcionando, e olhando a implementação tudo estava aparentemente correto:
def create_user(params) do
User
|> User.changeset(params)
|> put_assoc(:personal_info, params.personal_info)
|> Repo.create()
end
Debugando o código, vi que o problema era que ao executar o create_user
, o changeset do personal_info
não era executado. Então fui ver na documentação, e vi que a put_assoc
exige que os parâmetros tenham sido validados pelo changeset
antes da chamada da função, então o que eu precisava fazer era o seguinte:
def create_user(params) do
User
|> User.changeset(params)
|> put_assoc(:personal_info, build_personal_info(params))
|> Repo.create()
end
defp build_personal_info(%{
personal_info: personal_info
}) do
PersonalInfo
|> PersonalInfo.changeset(personal_info)
end
E dessa forma a validação passou a ser feita da maneira esperada. Porém, eu adicionei mais uma função privada no meu contexto. Então, eu fui atrás de uma forma melhor de resolver esse problema. A solução foi utilizar a cast_assoc
diretamente no changeset
do User
, pois ela faz a relação dos dados e trata as informações com o changeset
. E como os parâmetros já possuíam a chave personal_info
, eu não precisei informar qual parâmetro
deveria ser validado, pois a função já faz isso:
defmodule MyApp.Accounts.User do
...
schema "users" do
...
# Atente a necessidade da relação estar declarada no schema
has_one(:personal_info, PersonalInfo, on_delete: delete_all)
end
def changeset(user, attrs)
user
|> cast(attrs, @optional_fields ++ @required_fields)
|> validate_required(@required_fields)
|> cast_assoc(:personal_info, required: true)
end
Dessa forma, eu não precisei fazer nenhuma chamada no Contexto, nem criar uma nova função para validar os dados de PersonalInfo
ao salvar dados de uma nova pessoa usuária.
Top comments (2)
Excelente post ! Uma dúvida, qual era o erro que você obtinha anteriormente a essa nova abordagem ? Ou não havia erro, foi uma abordagem diferente e mais segura que optou por fazer ?
Então, nesse caso em específico não chegou a dar nenhum erro, pois os dados eram validados no frontend antes de enviar pra API. Mas caso chegasse alguma coisa invalida, iria dar erro do banco de dados e a API iria retornar 500.