AE
Ash Elixir•3y ago
harry

`AshPhoenix.Form` not applying changes

I am using forms as below:
def new(conn, _params) do
form = AshPhoenix.Form.for_create(Project.User, :new_account, api: Project.Accounts, as: "user")
render(conn, "new.html", changeset: form)
end

def create(conn, %{"user" => user_params} = _params) do
case AshPhoenix.Form.for_create(Project.User, :new_account, api: Project.Accounts, as: "user")
|> AshPhoenix.Form.submit(params: user_params) do
{:ok, user} ->
conn
|> put_flash(:info, "User created successfully.")
|> Project.UserAuth.log_in_user(user)

{:error, changeset} ->
render(conn, "new.html", changeset: changeset)
end
end
def new(conn, _params) do
form = AshPhoenix.Form.for_create(Project.User, :new_account, api: Project.Accounts, as: "user")
render(conn, "new.html", changeset: form)
end

def create(conn, %{"user" => user_params} = _params) do
case AshPhoenix.Form.for_create(Project.User, :new_account, api: Project.Accounts, as: "user")
|> AshPhoenix.Form.submit(params: user_params) do
{:ok, user} ->
conn
|> put_flash(:info, "User created successfully.")
|> Project.UserAuth.log_in_user(user)

{:error, changeset} ->
render(conn, "new.html", changeset: changeset)
end
end
And the action :new_account is as follows:
create :new_account do
accept([:email, :password])

change(
{Project.Changes.MaybeHashSecret, changeset_key: :new_password, resource_key: :password}
)
end
create :new_account do
accept([:email, :password])

change(
{Project.Changes.MaybeHashSecret, changeset_key: :new_password, resource_key: :password}
)
end
I would expect on submit that my change is hashing the secret however it isn't and the change is running when the form is created. The change is also below
def change(changeset, opts, _) do
changeset_key = Keyword.get(opts, :changeset_key, @default_changeset_key)
resource_key = Keyword.get(opts, :resource_key, @default_resource_key)

# TODO get working, not hashing secrets
with secret <- Ash.Changeset.get_argument_or_attribute(changeset, changeset_key),
true <- is_binary(secret),
hash <- Argon2.hash_pwd_salt(secret) do
Ash.Changeset.force_change_attribute(changeset, resource_key, hash)
else
_ -> changeset
end
end
def change(changeset, opts, _) do
changeset_key = Keyword.get(opts, :changeset_key, @default_changeset_key)
resource_key = Keyword.get(opts, :resource_key, @default_resource_key)

# TODO get working, not hashing secrets
with secret <- Ash.Changeset.get_argument_or_attribute(changeset, changeset_key),
true <- is_binary(secret),
hash <- Argon2.hash_pwd_salt(secret) do
Ash.Changeset.force_change_attribute(changeset, resource_key, hash)
else
_ -> changeset
end
end
Any ideas?
18 Replies
ZachDaniel
ZachDaniel•3y ago
I’m not sure why this wouldnt run on create, but the way that changes work is that they run when the changeset is validated, which happens on every form change. If you want to push something off to the action, in your change you do something like
fn changeset, _ ->
Ash.Changeset.before_action(fn changeset ->
…your code here
end
end
fn changeset, _ ->
Ash.Changeset.before_action(fn changeset ->
…your code here
end
end
You should use before action hooks for anything intensive, anything that hits a database for example, and for anything you want to happen exactly once.
harry
harryOP•3y ago
I'm not sure why it isn't but it is inserting the passwords in plain text
ZachDaniel
ZachDaniel•3y ago
I suspect its something in your with block falling through:
with secret <- Ash.Changeset.get_argument_or_attribute(changeset, changeset_key),
true <- is_binary(secret),
hash <- Argon2.hash_pwd_salt(secret) do
Ash.Changeset.force_change_attribute(changeset, resource_key, hash)
else
_ -> changeset
end
with secret <- Ash.Changeset.get_argument_or_attribute(changeset, changeset_key),
true <- is_binary(secret),
hash <- Argon2.hash_pwd_salt(secret) do
Ash.Changeset.force_change_attribute(changeset, resource_key, hash)
else
_ -> changeset
end
harry
harryOP•3y ago
Yeah looks like it is as it executes 3 times
ZachDaniel
ZachDaniel•3y ago
If you wrap it in before_action/1 it will work the way you expect 🙂 But I'd also advise using different keys to avoid this potential problem in the future. Or alternatively don't have a fallthrough clause
harry
harryOP•3y ago
it looks like this now,
Ash.Changeset.before_action(changeset, fn changeset ->
with secret <-
Ash.Changeset.get_argument_or_attribute(changeset, changeset_key) |> IO.inspect(),
true <- is_binary(secret),
hash <-
Argon2.hash_pwd_salt(secret) |> IO.inspect() do
Ash.Changeset.force_change_attribute(changeset, resource_key, hash)
else
_ -> changeset
end
end)
Ash.Changeset.before_action(changeset, fn changeset ->
with secret <-
Ash.Changeset.get_argument_or_attribute(changeset, changeset_key) |> IO.inspect(),
true <- is_binary(secret),
hash <-
Argon2.hash_pwd_salt(secret) |> IO.inspect() do
Ash.Changeset.force_change_attribute(changeset, resource_key, hash)
else
_ -> changeset
end
end)
ZachDaniel
ZachDaniel•3y ago
That looks right to me 🙂
harry
harryOP•3y ago
the secret is coming out as nil I figured it out
ZachDaniel
ZachDaniel•3y ago
🥳
harry
harryOP•3y ago
I had the wrong changeset key lol that was the issue all along 😭
ZachDaniel
ZachDaniel•3y ago
😆 Still a good lesson to learn about before_action/2
harry
harryOP•3y ago
Yeah
ZachDaniel
ZachDaniel•3y ago
Because imagine if you had a change that created a related thing in a database somewhere if you didn't wrap it in before_action/2 you'd create one for every keystroke they did on the form 😆
harry
harryOP•3y ago
😆 That reminds me of another issue I had, let me make a new forum thread
ZachDaniel
ZachDaniel•3y ago
As the first user of our new support forums stuff, can you tell me if its possible for you to close this post? Right click on it in the sidebar and select "close". That may be something that only administrators can do.
harry
harryOP•3y ago
The person who made it can close it, so yeah I can
ZachDaniel
ZachDaniel•3y ago
Nice. I wonder if we should also add a solved tag ...
harry
harryOP•3y ago
Could be nice for people searching? With a little green tick 🤣

Did you find this page helpful?