One form, multiple models stored in database

I’m trying to build a signup form which is able to create multiple models. Not only needs it to create a User but also creates an Organization.

I’m trying to find the best way to handle this. I’m following some of the advice from this talk: Controller Control: Designing Domains for Web Applications - Gary Rennie, and this post: Beyond 10,000 Lines by keeping my controllers Repo free and moving most of the logic to services. My goals are to place as much of the logic in services which can be reused in other places as well. Next to that I’m also keeping my schema’s really small, and only describe the tables in the database. This in preparation already for the next version of Phoenix, which I have understood is going in that direction.

Now I have two base services already in place, one for creating a User and one for creating an Organization.
To accomplish what I want with this page I have created a separate service that uses Ecto.Multi to call the other two services like this

    defmodule Erry.Signups.Signup do
      def create(email, password, organization) do
        |>, fn _ ->
, password)
        |>, fn %{user: user} ->
, user)
        |> Erry.Repo.transaction
        |> handle_new_signup

      defp handle_new_signup({:ok, results}) do
        user = results.user
        {:ok, user}

      defp handle_new_signup({:error, _, changeset, _}) do
        {:error, changeset}

And from my controller I call

    case Erry.Signups.Signup.create(email, password, organization) do
      {:ok, _user} -> redirect(conn, home_path(conn, :index))
      {:error, changeset} -> render(conn, "new.html", changeset: changeset)

Now each service uses different schema’s which can have validations which can fail. But when using Eco.Multi I will only get the changeset of the failing call. This changeset though has not all the information given by the user using the form, so it can’t be used again to populate the form again with errors being shown. I have thought about adding a separate schema for the signup flow like this:

defmodule Erry.Signup do
  use Erry.Web, :model

  embedded_schema do
     field :email, :string
     field :password, :string
     field :organization_name, :string

  def changeset(struct, params \\ %{}) do
    |> cast(params, [:email, :password, :organization_name])

But I’m not really sure if that is the best way to go or how to integrate it with the rest.


1 Like

I think you’re talking about a similar problem to what I was asking about last night:



Btw, we just went through an example in the mailing list too:!topic/elixir-ecto/_QHS-IY-sQY

Please write about such examples (articles, blogs, docs, etc) if you find they are useful so it helps people doing similar in the future.