Hello! I am new to the Elixir world and I’d appreciate some help to understand how associations work.
Scenario:
defmodule Pokemon.Trainer do
schema "trainers" do
# fields
has_many :pokemons, on_replace: :nilify
has_many :badges, on_replace: :nilify
has_one :hometown, on_replace: :nilify
end
def changeset(trainer, attrs) do
# regular cast and validations
|> cast_assoc(:pokemons)
|> cast_assoc(:badges)
|> cast_assoc(:hometown)
end
end
At some point I’ll get a JSON with all the nested information.
If the information of any child (ex: Pokemon level) changes, I want to perform an update. Otherwise, do nothing.
# in a service
def check_trainer_data([trainer | trainers]) do
# after fetching JSON, decoding, etc
pkmtrainer = %{
name: trainer["name"],
locale: trainer["locale"],
online_trainer_id: trainer["online_id"],
pokemons: Pokemon.PokemonParseService(trainer), #returns the list of pokemons
badges: Pokemon.BadgeParseService(trainer), #returns the list of badges
hometown: Pokemon.HometownParseService(trainer), #returns hometown
}
case Repo.get_by(Trainer, online_trainer_id: trainer["online_id]) do
nil -> # creates a trainer; cast_assoc worked
a_trainer ->
a_trainer
|> Repo.preload([:pokemon, : badges, :hometown])
|> Trainer.changeset(pkmtrainer)
# here is my question ; attempts inserted here
|> Repo.update()
end
In order to create or update the associated data, it looks like I could use put_assoc.
-
Attempt 1: Ecto.Changeset.put_assoc(:pokemons, Pokemon.PokemonParseService(trainer, a_trainer))
This ParseService returns the list of pokemons for a specific JSON and associated the id of the persisted trainer. It works, but I noticed it will update the children structure (pokemons) every time, even if there are no changes. Is this expected? -
Attempt 2 - I went back to the Trainer class and created a custom changeset, receiving the associations parameters:
def changeset(trainer, pokemons, badges, hometown, attrs)
# default cast and validation
|> put_assoc(:pokemons, pokemons)
|> put_assoc(:badges, badges)
|> put_assoc(:hometown, hometown)
end
And I called it at the placeholder. It also worked, but with the same problem - updating all the children every time.
Is there a way to update the associated structures only when there are real changes? Is there a more appropriated way to do this?
Thank you very much for your help and patience!
Best,