sheerlox

sheerlox

Currently migrating from 2.x to 3.x!

My test suite detected a behavior change that I couldn’t explain by looking at the upgrade doc or the new documentation, so I’m really not sure how I should handle this.

I got an update action that starts the email change process, which is basically just my Ash version of what is found in the mix phx.gen.auth generator.

If the email is already taken, I add an error with Changeset.add_error/2 in the first before_transaction hook:

update :request_email_change do
  description """
  Create a user token for changing the credential's email and send a confirmation email.
  """

  accept [:email]

  argument :current_password, :string, allow_nil?: false, sensitive?: true

  argument :update_email_url_fun, :function,
    allow_nil?: false,
    description: """
    A function taking the confirmation token as its only argument and returning the URL to send to the user.
    """

  validate changing(:email)

  change fn changeset, %{actor: actor} ->
    changeset
    |> Changeset.before_transaction(fn changeset ->
      case changeset
           |> Changeset.get_attribute(:email)
           |> UserCredential.get_by_email(actor: actor) do
        {:ok, _} ->
          Changeset.add_error(
            changeset,
            Ash.Error.Changes.InvalidArgument.exception(
              field: :email,
              message: "has already been taken"
            )
          )

        {:error, _} ->
          changeset
      end
    end)
    |> Changeset.before_transaction(&validate_current_password/1)
    |> Changeset.before_action(fn changeset ->
      current_email = Changeset.get_data(changeset, :email)
      update_email_url_fun = Changeset.get_argument(changeset, :update_email_url_fun)

      {:ok, applied_credential} = Ash.Changeset.apply_attributes(changeset)

      Accounts.deliver_credential_update_email_instructions(
        Ash.load!(applied_credential, [:user], actor: actor),
        current_email,
        update_email_url_fun
      )

      # clear the change so no update happens yet
      Changeset.clear_change(changeset, :email)
    end)
  end
end

I’m almost 100% positive that previously this prevented the execution of the next hooks.

The following test makes sure the email validation uniqueness works, and was passing before upgrading to 3.0:

test "validates email uniqueness", %{user: user, credential: credential} do
  %{email: email} = user_registration_fixture().credential

  assert_raise Ash.Error.Invalid,
               ~r/email: has already been taken/,
               fn ->
                 UserCredential.request_email_change!(
                   credential,
                   email,
                   valid_user_credential_password(),
                   &update_email_url_fun/1,
                   actor: user
                 )
               end
end

Instead of raising the expected Ash.Error.Invalid as before, I know get a Ash.Error.Unknown because there is a match error in the before_action hook (when matching {:ok, applied_credential}), despite my InvalidArgument error being present in the changeset:

%Ash.Error.Unknown{
  changeset: "#Changeset<>",
  errors: [
    %Ash.Error.Unknown.UnknownError{
      error: %MatchError{
        term: {:error,
         #Ash.Changeset<
           domain: TalentIdeal.Accounts,
           action_type: :update,
           action: :request_email_change,
           attributes: %{
             email: #Ash.CiString<"user-576460752303423358@example.com">
           },
           relationships: %{},
           arguments: %{ ... },
           errors: [
             %Ash.Error.Changes.InvalidArgument{
               field: :email,
               message: "has already been taken",
               value: nil,
               splode: nil,
               bread_crumbs: [],
               vars: [],
               path: [],
               stacktrace: #Splode.Stacktrace<>,
               class: :invalid
             }
           ],
           data: #TalentIdeal.Accounts.UserCredential< ... >,
           valid?: false
         >}
      },
      field: nil,
      splode: Ash.Error,
      bread_crumbs: [],
      vars: [],
      path: [],
      stacktrace: #Splode.Stacktrace<>,
      class: :unknown
    }
  ]
}

Am I missing something or is there indeed a behavior change, and is it expected? Is it documented somewhere I didn’t find?

Thanks in advance!

Showing Posts 1 to 5

zachdaniel

zachdaniel

Creator of Ash

Can you try configuring in the action atomic_upgrade? false and see if that resolves the issue? This will help isolate the cause.

zachdaniel

zachdaniel

Creator of Ash

I have a suspicion of what the error is. Can you try main of ash and see if that resolves the issue?

zachdaniel

zachdaniel

Creator of Ash

Actually…I’m not so sure that is the issue :slight_smile: The action you’re showing couldn’t get an atomic upgrade anyway because of the function change. So the issue must be somewhere else.

zachdaniel

zachdaniel

Creator of Ash

Alright, try main now, I think I fixed the actual issue :slight_smile:

sheerlox

sheerlox OP

The first two solutions didn’t change anything, but your latest 2316b7b commit fixed the issue.

Thanks again Zach, you rock!

P.S. I’m still having issues believing you’re not a super-AI from the future, how do you do it :joy:

— All posts loaded —

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
FlyingNoodle
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews