I have a subscription like this.
defmodule Rebirth.Subscription do
use Rebirth.Web, :model
schema "subscriptions" do
...
belongs_to :user, Rebirth.User
...
end
...
def update_user(model, params \\ :empty) do
model
|> cast(params, @required_fields, @optional_fields)
|> cast_assoc(:user, required: false)
end
end
I want to associate a user to the subscription
So I tried
Rebirth.Subscription.update_user(subscription, %{user_id: 1})
or
Rebirth.Subscription.update_user(subscription, %{user: user})
When I run it I get the following error:
** (ArgumentError) unknown assoc `user` in `cast_assoc`
How do I update the user_id?
Thanks!
cast_assoc
is used to "cast associated model" and can be used only with has_one
and has_many
. belongs_to
relation defines the foreign id in the model where it is invoked. has_many
and has_one
rely on "the other" object having foreign key.
In case you are creating object that has many other objects it makes sense to check all of them if they are valid. cast_assoc
will invoke cast
in their respective modules.
Your user can have many subscriptions (probably, I am guessing here), so it doesn't make sense to create user when creating subscription and check if the user is valid via cast_assoc
. Usually in this case the user will exist in database already.
In your case you only want to check if associated model exists in the cast, so you should use:
|> assoc_constraint(:user)
This does not validate user, but checks if given user_id
exists in the database. Now, when you want to update the subscription for a user you can do this:
user = Repo.get(User, id)
subscription = Ecto.build_assoc(user, :subscriptions, other_fields_as_map)
Note it requires has_one
or has_many
on the user model.
Or you can simply update the user id as you tried before:
Rebirth.Subscription.update_user(subscription, %{user_id: 1})
and this time it will check the database if given user id exists, but You won't be able to pass entire user object here.
And if you want to update associated user, you will have to do it explicitly in two steps. a) get the user, b) update the user using changeset defined in its module.
Final note, if you don't make separate validation for updating users (and I don't think you should in this scenario), it would be good to rename the function from update_user
to changeset
. The same changeset can be used for creating and updating models.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With