As @peerreynders hinted, the right way to think about this is not how to invoke some other controller action to complete user registration, but to place the concerns of what all should happen when creating a user inside of a well named module and function. Check out our Context guide for more details around this idea, but for your specific case, let’s imagine your user/session controller called into something like this:
defmodule MyAppWeb.SessionController do
def create(conn, %{"user" => user_params}) do
case Accounts.register_user(user_params) do
{:ok, user} ->
conn
|> put_flash(:info, "Welcome aboard!")
|> signin_user(user)
|> redirect(to: user_todo_path(conn, :index, user)
{:error, changeset} -> render("new.html", changeset: changeset)
end
end
end
With something like Accounts.register_user(...)
our phoenix code doesn’t need to know or care about what all should happen when a user signs up. We can place all the concerns of this inside a function that accomplishes everything that should happen. Now later if we want to send welcome emails, we have a perfect spot for it. Likewise, if we want to offer registration over crud forms, as well as react consuming a JSON API, as well as react consuming a GraphQL Absinthe schema, all web endpoints simply call into the same function. Diving deeper, our Accounts
and Todos
contexts could look something like this:
defmodule MyApp.Accounts do
alias MyApp.Accounts.User
alias MyApp.Repo
alias Ecto.Multi
def register_user(params) do
Multi.new()
|> Multi.insert(:user, User.changeset(%User{}, params))
|> Multi.run(:seed, fn %{user: user} -> Todos.seed_starting_todos(user) end)
|> Repo.transaction()
end
end
defmodule MyApp.Todos do
alias MyApp.Repo
alias MyApp.Todos.Todo
def seed_starting_todos(user) do
Repo.insert_all(Todo, [
Ecto.build_assoc(user, :todos, title: "My first todo"),
Ecto.build_assoc(user, :todos, title: "My second todo"),
Ecto.build_assoc(user, :todos, title: "My third todo"),
])
end
def create_todo(user, params) do
...
end
end
Now instead of jumping through hoops to try to chain different controller actions or have the client be concerned with what should be POST’d to once a user is registered, we have a natural place to handle it. Likewise, when we build out the Todo controller, we can define function for managing todos and friends inside a module that wraps up all the shared todo functionality. Make sense?