I have (football) Teams and Games :
schema "games" do
field :away_team_score, :integer
field :competition, :string
field :game_datetime, :utc_datetime
field :home_team_score, :integer
field :round, :string
belongs_to :home_team, LvdnApi.Fixtures.Team
belongs_to :away_team, LvdnApi.Fixtures.Team
timestamps()
end
schema "teams" do
field :name, :string
has_many :games, LvdnApi.Fixtures.Game
timestamps()
end
I need to use put_assoc
to persist the association in my DB when I create a game. I get the attributes for a new game from a form in which I get the ids of home_team
and away_team
.
home_team
and away_team
can’t be null nor empty; I need to make sure of this when both creating and updating any record.
But I don’t really get how to do this: where should I use put_assoc/3
? in the changeset ? in my change_game
method ? When do I retrieve the Team
with their id ?
also the fact that I have two different fields of type Team
makes me even more confused. How can I make sure each associated team will be persisted in the right field ?
If your team already exist when creating your team, then you don’t use put_assoc
at all. Populate :home_team_id
and :away_team_id
and it should work.
2 Likes
Yep. The database will complain if there’s no record to be found by the given id. You might want to use assoc_constraint
though if you want nice errors in your changeset for those cases, where this happens.
OK thank you
But what is put_assoc
for then (e.g. in opposition to cast_assoc
) ? In the book Programming Phoenix , Chris McChord uses put_assoc
even though the user
associated the video
he is creating already exists.
So put_assoc and cast_assoc do result in basically the same thing. They add associations to a changeset, which are also saved besides the root schema. This is especially useful from the “has_one/has_many” side of things, where you not only save the schema, but must also save/update the linked association, because it has the foreign key field. The other use case is if you have actual changes to the schema and its associations at the same time.
The difference between those two functions is that one is casting incoming data (equivalent to cast/4
), while put_assoc
is more like put_change
, where incoming data is not cast into a runtime format, but simply accepted as is.
1 Like
OK I see, but if I use assoc_constraint
, how do I make sure the team ID I got exists in the DB ?
You don’t. The db does. If you setup the column as a foreign key the db will complain if you try to insert an id, which does not exist on the other table. assoc_constraint
just gives you nice changeset errors instead of raised errors if the db does indeed complain.
2 Likes
oh that is great ! Thank you very much @LostKobrakai
Actually I have one last question: how do I use assoc_contraint
as I have two fields that belongs_to the same model ?
def changeset(game, attrs) do
game
|> cast(attrs, [:home_team_score, :away_team_score, :competition, :round, :game_datetime, :home_team, :away_team])
|> validate_required([:competition, :round, :game_datetime, :home_team, :away_team])
|> assoc_constraint(:team)
end
this way will it check for both home_team
and away_team
?
Set it up for both fields. It’s just a detail that both fields happen to link to the same foreign table.
1 Like