wemgl

wemgl

Creating custom controller callbacks with Pow

I’m working on an app that uses Pow to handle user authentication. I was able to get it working by following the documentation, but I ran into an issue that I don’t see a clear solution for.

The application is for a subscription service where new users are given a free trial after signing up. I use Pow to create the user, which works fine. Now, I’m trying to associate the newly created user with a subscription using the controller callback feature from the Phoenix controllers section of the README. Here’s my implementation so far:

defmodule AddSubscription.Phoenix.ControllerCallbacks do
  use Pow.Extension.Phoenix.ControllerCallbacks.Base

  require Logger

  @impl true
  def before_respond(Pow.Phoenix.RegistrationController, :create, {:ok, user, conn}, _config) do
    Logger.debug("user registration before_respond: #{inspect(user)}")
    with {:ok, user} <- Trumpet.insert_subscription(%{user_id: user.id}) do
      {:ok, user, conn}
    end
  end
end

I’ve also written a controller test to exercise the behavior works as intended:

defmodule Pow.Phoenix.RegistrationControllerTest do
  use TrumpetWeb.ConnCase

  describe "POST /registration" do
    test "creates a user with a subscription", %{conn: conn} do
      email = "wembley.gl@gmail.com"
      post(
        conn,
        "/registration",
        %{
          user: %{
            email: email,
            password: "test1234567890",
            confirm_password: "test1234567890",
          }
        }
      )
      user = Trumpet.get_user_by_email_with_subscription(email)
      assert user.subscription
      assert Trumpet.Subscription.trial?(user.subscription)
    end
  end
end

The user creation works as expected, but the controller callback isn’t firing, so the assertion for user.subscription fails. I’ve taken a look at the Extensions section for Pow, from here, and looked at the implementation for other extensions, like PowPasswordReset, and it looks like an extension should be implemented as a library application, is that right? Also, how do I configure Pow to register an extension once it’s created? I apologize if this is in the documentation and I’m missing it.

Marked As Solved

danschultzer

danschultzer

Pow Core Team

The callbacks is the wrong place to deal with this. You would want it to be inserted in a transaction so if the subscription insert fails, the user won’t be created. There’re multiple ways to deal with it, but if all users inserted needs to have a subscription created along it, then I would keep it simple and just deal with it in the user changeset:

defmodule MyApp.Users.User do
  use Ecto.Schema
  use Pow.Ecto.Schema

  schema "users" do
    has_one :subscription, MyApp.Users.Subscription

    pow_user_fields()

    timestamps()
  end

  def changeset(user_or_changeset, attrs) do
    user
    |> pow_changeset(attrs)
    |> maybe_add_subscription()
  end

  defp maybe_add_subscription(changeset) do
    case Ecto.get_meta(changeset.data, :state) do
      :built  -> add_subscription(changeset)
      :loaded -> changeset
    end
  end
  
  defp add_subscription(changeset) do
    Ecto.Changeset.cast_assoc(changeset, :subscription, with: &MyApp.Users.Subscription.changeset/2)
  end
end

If you need more control over the flow, then I would either set up a custom controller and/or custom context module.

(Also, as you guessed the controller callbacks module you’ve set up is only for custom extensions)

Also Liked

wemgl

wemgl

Thanks for the quick response. You make a valid point. I was caught up trying to leverage the functionality in Pow, that I forgot that I was able to make modifications to the User changeset directly, since all I did to add the Pow support was add pow_user_fields and the various use macros to bring in functions.

danschultzer

danschultzer

Pow Core Team

There is a duplicate thread that I answered this in: POW: Custom controller doubts - #2 by danschultzer

Where Next?

Popular in Questions Top

chokchit
** (DBConnection.ConnectionError) connection not available and request was dropped from queue after 2733ms. You can configure how long re...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

Other popular topics Top

malloryerik
Hi, this is for people who, like me, have had some friction using .html.heex templates in VSCode. The solution seems to be, in a hyphena...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 47930 226
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
Qqwy
Update: How to use the Blogs &amp; Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 126479 1222
New

We're in Beta

About us Mission Statement