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
schema "teams" do
field :name, :string
has_many :games, LvdnApi.Fixtures.Game
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
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
:away_team_id and it should work.
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
put_assoc is more like
put_change, where incoming data is not cast into a runtime format, but simply accepted as is.
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.
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
|> 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])
this way will it check for both
Set it up for both fields. It’s just a detail that both fields happen to link to the same foreign table.