I am writing a simple CRUD app in Phoenix, where admins, upon creating a new organisation are allowed to provision it with an initial staff member account.
Effectively the relationship between Organisations and Users is many to many.
I came up with the following:
User schema:
defmodule MyApp.User do use MyApp.Web, :model schema "users" do field :name, :string field :email, :string field :password, :string, virtual: true field :password_hash, :string end def changeset(...) # validate email, password confirmation etc.
Organisation schema:
defmodule MyApp.Org do use MyApp.Web, :model schema "orgs" do field :official_name, :string field :common_name, :string has_many :org_staff_users, MyApp.OrgStaffUser has_many :users, through: [:org_staff_users, :user] end def changeset(model, params \\ :empty) do model |> cast(params, ~w(official_name common_name), []) end def provisioning_changeset(model, params \\ :empty) do model |> changeset(params) |> cast_assoc(:org_staff_users, required: true) end
Junction table
org_staff_users
and the corresponding Ecto Schema withuser_id
andorg_id
Controller with the following
new
action:def new(conn, _params) do data = %Org{org_staff_users: [%User{}]} changeset = Org.provisioning_changeset(data) render(conn, "new.html", changeset: changeset) end
Template with the following excerpt:
<%= form_for @changeset, @action, fn f -> %> <%= if @changeset.action do %> <div class="alert alert-danger"> <p>Oops, something went wrong! Please check the errors below:</p> <ul> <%= for {attr, message} <- f.errors do %> <li><%= humanize(attr) %> <%= message %></li> <% end %> </ul> </div> <% end %> <%= text_input f, :official_name, class: "form-control" %> <%= text_input f, :common_name, class: "form-control" %> <%= inputs_for f, :org_staff_users, fn i -> %> <%= text_input f, :email, class: "form-control" %> <%= text_input f, :password, class: "form-control" %> <%= text_input f, :password_confirmation, class: "form-control" %> <% end %> <%= submit "Submit", class: "btn btn-primary" %> <% end %>
So far so good, the form displays nicely.
The problem is, I don't really understand what should be the canonical way of building the changeset I'm about to insert on create
, while being able
to pass it again to the view upon validation errors.
It is unclear whether I should use one changeset (and how?) or explicitly
three changesets per each entity (User
, Org
and the junction table).
How do I validate the changes for such combined form, given that each model / schema has its own specific validations defined?
The params I receieve upon submitting the form are all within %{"org" => ...}
map, including the ones that are in fact related to a user
. How should I
create the form properly?
I have read the recently updated http://blog.plataformatec.com.br/2015/08/working-with-ecto-associations-and-embeds/ but I remain confused regardless.
FWIW, I am on Phoenix 1.0.4, Phoenix Ecto 2.0 and Phoenix HTML 2.3.0.
Any tips would be greatly appreciated.