I’m using ex_admin to maintain a couple of tables (crud). I am trying to develop some task-based processes https://tech-stories.com/2011/09/15/getting-more-business-value-with-task-based-ui/ now where these tables are maintained. See the picture in this message: https://elixirforum.com/t/please-help-me-persuade-a-java-cto-that-elixir-is-the-right-choice/13067/69. This process is for creating a new user (see picture below), eventually add roles (that are coupled to the user also, this is the next form that appears after pressing the left button), and authorisations (last form).
The formdefinitions are supplied via a channel (json), the forminput is returned via the same channel. I would like to use ecto to insert the records into postgress. The changeset function expects a “model” parameter that looks like this when I IO.inspect it inserting a record via ex_admin:
%Auth.User{
__meta__: #Ecto.Schema.Metadata<:built, "users">,
email: nil,
id: nil,
inserted_at: nil,
name: nil,
password: nil,
password_hash: nil,
password_repeat: nil,
roles: #Ecto.Association.NotLoaded<association :roles is not loaded>,
updated_at: nil,
usergroup: #Ecto.Association.NotLoaded<association :usergroup is not loaded>,
usergroup_id: nil
}
My question is how to create this parameter. The schema + changeset functions are here:
defmodule Auth.User do
use Ecto.Schema
import Ecto.Changeset
import Ecto.Query
schema "users" do
field :name, :string
field :email, :string
field :password, :string, virtual: true
field :password_repeat, :string, virtual: true
field :password_hash, :string
belongs_to :usergroup, Admin.Usergroup
many_to_many :roles, Admin.Role, join_through: Admin.UserRole, on_replace: :delete
timestamps()
end
def changeset(model, params \\ :invalid) do
model
|> cast(params, ~w(name email password usergroup_id))
end
def changeset_create(model, params \\ :invalid) do
model
|> cast(params, ~w(name email password usergroup_id))
|> validate_required([:name, :password, :email])
|> validate_length(:name, max: 20)
|> unique_constraint(:name)
|> unique_constraint(:email)
|> validate_length(:password, min: 8)
|> validate_format(:email, ~r/@/)
|> put_pass_hash()
|> add_roles(params)
end
def changeset_update(model, params \\ :invalid) do
model
|> cast(params, ~w(name email))
|> validate_required([:name, :email])
|> validate_format(:email, ~r/@/)
|> validate_length(:name, max: 20)
|> unique_constraint(:name)
|> unique_constraint(:email)
|> add_roles(params)
end
def add_roles(changeset, params) do
# see https://github.com/smpallen99/ex_admin, code had to be customized
if Map.get(params, :role_ids, []) !== [""] do
ids = params.role_ids |> Map.keys() |> Enum.map(fn atom -> atom |> Atom.to_string() |> String.to_integer() end)
roles = Admin.Repo.all(from r in Admin.Role, where: r.id in ^ids)
put_assoc(changeset, :roles, roles)
else
put_assoc(changeset, :roles, [])
end
end
def put_pass_hash(changeset) do
case changeset do
%Ecto.Changeset{valid?: true, changes: %{password: pass}} ->
put_change(changeset, :password_hash, Comeonin.Bcrypt.hashpwsalt(pass))
_ ->
changeset
end
end
end