Don't show existing value of form field

I have a sensitive value that I don't want displayed again, but I want an input to be able to update the value. Is there an option that exists for that?
31 Replies
ZachDaniel
ZachDaniel2y ago
Hmm…there are definitely ways. You can track the value yourself in an assign And then do value={@assign} And then on change you can assign to that assign
michaelst
michaelstOP2y ago
so I found this exclude_fields_if_empty now I just need to have the current values not selected oh maybe just need to modify the Api.get so I'm trying to override the action to deselect fields but I don't know if I'm setting this up right
|> QueryDesk.Api.get!(id, action: :no_sensitive_info, load: [:credentials, :agent])
|> QueryDesk.Api.get!(id, action: :no_sensitive_info, load: [:credentials, :agent])
the action
read :no_sensitive_info do
get? true
prepare build(deselect: [:name])
end
read :no_sensitive_info do
get? true
prepare build(deselect: [:name])
end
kernel
kernel2y ago
mmm it's simpler than this isnt it action has takes an argument argument updates the attribute just don't show the secret field in a form
michaelst
michaelstOP2y ago
Oh ya that makes sense, thanks! ok I got it kinda of working, only problem is I can't quite figure out how to make it not override the old value if the value is empty
argument :new_keyfile, :string
change set_attribute(:keyfile, arg(:new_keyfile))
argument :new_keyfile, :string
change set_attribute(:keyfile, arg(:new_keyfile))
I tried set_when_nil?: false but that never lets it get set
ZachDaniel
ZachDaniel2y ago
🤔 There are options you can pass into the form when you create it to modify the paramus might want to check the docs to see those options but you could also update the params before sending them in.
michaelst
michaelstOP2y ago
I was looking in the docs and not seeing anything, I also tried exclude_fields_if_empty but I don't understand the behavior as it didn't work as I thought it would so even removing the empty values from params still didn't work, because I have the action always setting it, the empty value still replaces the old value is there a way to tell an action to only change if a value is passed?
ZachDaniel
ZachDaniel2y ago
Oh are you using change set_attribute? change set_attribute(:foo, arg(:foo), set_when_nil?: false)
michaelst
michaelstOP2y ago
ya, the set_when_nil?: false is making it so the field never gets set even the value is present, not sure what is going on there this is what I finally got working
form = socket.assigns.form

non_empty_params =
params
|> Enum.filter(fn {_k, v} -> v != "" end)
|> Map.new()

params =
non_empty_params
|> Map.put("cacertfile", non_empty_params["new_cacertfile"] || form[:cacertfile].value)
|> Map.put("keyfile", non_empty_params["new_keyfile"] || form[:keyfile].value)
|> Map.put("certfile", non_empty_params["new_certfile"] || form[:certfile].value)
form = socket.assigns.form

non_empty_params =
params
|> Enum.filter(fn {_k, v} -> v != "" end)
|> Map.new()

params =
non_empty_params
|> Map.put("cacertfile", non_empty_params["new_cacertfile"] || form[:cacertfile].value)
|> Map.put("keyfile", non_empty_params["new_keyfile"] || form[:keyfile].value)
|> Map.put("certfile", non_empty_params["new_certfile"] || form[:certfile].value)
then I pass that to submit
ZachDaniel
ZachDaniel2y ago
🤔 I bet set_when_nil isn't handling the empty string so we probably need to make set_when_nil cast the value as input to see if it results in a nil value I'd suggest doing something like:
def delete_if_empty(map, key) do
if Map.get(map, key) == "" do
Map.delete(map, key)
else
map
end
end
def delete_if_empty(map, key) do
if Map.get(map, key) == "" do
Map.delete(map, key)
else
map
end
end
And then you can do delete_if_empty("cacertfile", ...) didn't realize you have new_cacertfile so maybe not 🤷‍♂️
michaelst
michaelstOP2y ago
the delete_if_empty might be good actually, because now I can't set values to empty now hahaha, with that function I can delete specific keys
kernel
kernel2y ago
I just have a custom changeset (as I have to encrypt my field)
michaelst
michaelstOP2y ago
I also encrypt my field, but that happens in a type But got it all working, appreciate the help
ZachDaniel
ZachDaniel2y ago
I've actually had to change my type-based value encryption to have it done as a change on the resource because Ecto internally was double-encrypting the same value
michaelst
michaelstOP2y ago
defmodule QueryDesk.Type.EncryptedString do
use Ash.Type

def graphql_input_type(), do: :string
def graphql_type(), do: :string

@impl Ash.Type
def storage_type(), do: :binary

@impl Ash.Type
defdelegate constraints, to: Ash.Type.String, do: :constraints

@impl Ash.Type
defdelegate apply_constraints(value, constraints), to: Ash.Type.String, do: :apply_constraints

@impl Ash.Type
def cast_input(value, _constraints) do
Ecto.Type.cast(Cloak.Type.EncrytpedString, value)
end

@impl true
def cast_stored(value, _constraints) do
Ecto.Type.load(Cloak.Type.EncrytpedString, value)
end

@impl true
def dump_to_native(value, _constraints) do
Ecto.Type.dump(Cloak.Type.EncrytpedString, value)
end
end

defmodule Cloak.Type.EncrytpedString do
use Cloak.Ecto.Binary, vault: QueryDesk.Vault
end
defmodule QueryDesk.Type.EncryptedString do
use Ash.Type

def graphql_input_type(), do: :string
def graphql_type(), do: :string

@impl Ash.Type
def storage_type(), do: :binary

@impl Ash.Type
defdelegate constraints, to: Ash.Type.String, do: :constraints

@impl Ash.Type
defdelegate apply_constraints(value, constraints), to: Ash.Type.String, do: :apply_constraints

@impl Ash.Type
def cast_input(value, _constraints) do
Ecto.Type.cast(Cloak.Type.EncrytpedString, value)
end

@impl true
def cast_stored(value, _constraints) do
Ecto.Type.load(Cloak.Type.EncrytpedString, value)
end

@impl true
def dump_to_native(value, _constraints) do
Ecto.Type.dump(Cloak.Type.EncrytpedString, value)
end
end

defmodule Cloak.Type.EncrytpedString do
use Cloak.Ecto.Binary, vault: QueryDesk.Vault
end
this is how I'm doing it, is ecto double encrypting this?
ZachDaniel
ZachDaniel2y ago
Yes. Basically if you write the same value back to the encrypted type it won’t know not to encrypt it again
michaelst
michaelstOP2y ago
Hmm I've been using this for a while and have not had any issues
ZachDaniel
ZachDaniel2y ago
I don’t recall the specific issue, I’d just keep an eye out for it basically.
michaelst
michaelstOP2y ago
oh you weren't saying it will cause an issue, just doing double work
ZachDaniel
ZachDaniel2y ago
No, it caused an issue Because decrypting it no longer yielded the original value
michaelst
michaelstOP2y ago
hmm definitely haven't run into that
ZachDaniel
ZachDaniel2y ago
So for safety’s sake I made the unencrypted values into arguments and made a change that encrypts and writes the arguments when set. 🤷‍♂️ not sure what’s different about mine and your app/implementation.
michaelst
michaelstOP2y ago
is there a way to make an argument only run the change if set? I was running into that issue of it always setting the value to null if not passed
ZachDaniel
ZachDaniel2y ago
But if it works for you then no worries.
ZachDaniel
ZachDaniel2y ago
GitHub
ash_hq/lib/ash_hq/changes/encrypt.ex at main · ash-project/ash_hq
The Ash Framework homepage and documentation site. - ash_hq/lib/ash_hq/changes/encrypt.ex at main · ash-project/ash_hq
ZachDaniel
ZachDaniel2y ago
So actually that just checks if a given attribute is being changed, and if so rewrites the change to the encrypted value Not using arguments, I lied 🙂
michaelst
michaelstOP2y ago
ah custom change
ZachDaniel
ZachDaniel2y ago
Yeah
michaelst
michaelstOP2y ago
maybe we need to add a change_if_set builtin or maybe that is what set_if_nil is for, but for some reason that was just never setting that value for me even when passed with a non nil value
ZachDaniel
ZachDaniel2y ago
Yeah I think that one is for empty strings in forms Is basically it’s own issue We’d need to cast the value to see if it would cast to nil An example of a place we might cause double encryption with your type TBH
\ ឵឵឵
\ ឵឵឵2y ago
set_when_nil? is unfortunately not very clearly named, and actually specifies the behaviour based on the existing value as opposed to the new value of the changeset.
ZachDaniel
ZachDaniel2y ago
Oh, right you are 🤦‍♂️

Did you find this page helpful?