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) endJunction table
org_staff_usersand the corresponding Ecto Schema withuser_idandorg_idController with the following
newaction:def new(conn, _params) do data = %Org{org_staff_users: [%User{}]} changeset = Org.provisioning_changeset(data) render(conn, "new.html", changeset: changeset) endTemplate 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.