Reputation: 69
I have a User schema
schema "users" do
field :name, :string
field :username, :string
has_one :user_role, UserRole
end
def changeset(%User{} = user, attrs) do
user
|> cast(attrs, [:name, :username])
|> validate_required([:name, :username])
|> unique_constraint(:username)
end
and the UserRole schema
schema "userroles" do
field :is_admin, :boolean, default: false
belongs_to :user, User
end
def changeset(%UserRole{} = user_role, attrs) do
user_role
|> cast(attrs, [:is_admin, :user_id])
|> validate_required([:is_admin])
end
They are both in the same context "Accounts", where I cast the associations.
#accounts.ex
def create_user(attrs \\ %{}) do
%User{}
|> User.changeset(attrs)
|> Ecto.Changeset.cast_assoc(:user_role, required: true)
|> Repo.insert()
end
Here is the UserController's new and create:
def new(conn, _params) do
changeset = Accounts.change_user(%User{})
render(conn, "new.html", changeset: changeset)
end
def create(conn, %{"user" => user_params}) do
case Accounts.create_user(user_params) do
{:ok, user} ->
conn
|> put_flash(:info, "User created successfully.")
|> redirect(to: user_path(conn, :show, user))
{:error, %Ecto.Changeset{} = changeset} ->
render(conn, "new.html", changeset: changeset)
end
end
I have a nested form for the User and the UserRole. If I enter all data, everything works as expected. Now, I want to hide the input for UserRole, because I don't want a user to set himself as "is_admin" (but if you are an admin, you should be able to create other admin accounts). So, there's no input for the UserRole anymore if you are a non-admin user. My expectations were that
What happened is: The user was created, but the associated user_role is "nil". I don't get why this happens. Can anybody explain this to me?
My solution was: Instead of giving the user a checkbox for the boolean :is_admin, I send a hidden input, setting it to false, but it seems not be the good way.
Upvotes: 1
Views: 223
Reputation: 1056
You can always use
Map.put_new(map, key, value)
in this case
before
case Accounts.create_user(user_params) do
use params = Map.put_new(user_params, :user_role, "anything")
what this will do is, if it finds the :user_role
in map, it will use same, if it doesn't find anything, it will use the value you specified.
it needs the value for user_role
because there is an association related to it. Though i feel it should be has_many
association, but your code shows its has_one
, so for every user
entry there should be user_role
associated to it.
If has_many
is to be used, belongs_to
should be in user
schema, and has_many
in user_role
schema
Upvotes: 1