Hi everyone,
I have been learning a bit more on Ecto and Phoenix. Specifically in how to handle a master/detail o parent/child associations and the corresponding Web Form.
My question: Is there a better way to handle this typical scenario than the one I implemented below?
In my journey I read about:
- Ecto associations, multi, cast_assoc, put_assoc, embeded_schemas, transactions
- Drab Library
Checktout many resources like:
- Phoenix, Ecto, Drab official documentation
- Different Forums: Medium, Elixir Forum
- What’s new in Ecto 2.0
- Others
Adding them up and based on my understanding of some topics I came out with the following:
Scenario
Phoenix: 1.3
Elixir: 1.6.1
Ecto: 2.2.8
Schema: Invoices --> has_many --> details, belongs_to
Context name: Documents
I used basic generator to generate both
This I changed:
Invoice controller: action new
def new(conn, _params) do
changeset = Documents.change_invoice(
%Invoice{
details: [%Multipartform.Documents.Detail{}]
}
)
render(conn, "new.html", changeset: changeset)
end
Documents api:
def add_records(%{invoice: invoice}, attrs) do
records =
Enum.map(attrs["details"], fn {_, d} ->
Map.put(d, "invoice_id", invoice.id)
end)
|> Enum.map(&Multipartform.Documents.Detail.changeset(
%Multipartform.Documents.Detail{},&1)
)
|> Enum.map(fn ch -> {:ok, _d} = Repo.insert(ch) end)
{:ok, records}
end
def save_invoice(invoice_changeset, attrs) do
Multi.new()
|> Multi.insert(:invoice, invoice_changeset)
|> Multi.run(:add_detail, &add_records(&1, attrs))
end
def create_invoice(attrs \\ %{}) do
invoice_changeset =
%Invoice{}
|> Invoice.changeset(attrs)
case Repo.transaction(save_invoice(invoice_changeset, attrs)) do
{:ok, %{invoice: invoice, add_detail: _details}} ->
{:ok, invoice}
{:error, _failed_operation, _failed_value, _changes_so_far} ->
{:error, invoice_changeset}
end
end
The view part is very straight forward and simplified using Drab to add more details in the UI.
Even when the Ecto documentation seemed very clear I was not able to figure out ecto cast_assoc, put_assoc and how they work together. Another challenge was understanding ecto Multi.
Can’t wait to see the @darinwilson Ecto Book.
Thanks for your comments and suggestions.