fireproofsocks

fireproofsocks

I’m working on a table to store shipping addresses. I would like to add a fingerprint of each address so that I can more easily tell whether or not a given address has already been added. For simplicity, let’s assume that I’ve worked out a nice fingerprinting algorithm to normalize my addresses and identify them via a single string… let’s say this function is named simply fingerprint(address).

My question is about Ecto and changesets: how and where can I add this field to the database record when I save it? I’m unclear on how the cast and other functions are working inside the changeset function.

If I try to save a new address and its fingerprint matches an existing address, the save operation should fail.
If I try to edit an existing address and change it so it matches an existing address, the update operation should fail.

Any help on this would be appreciated… I’m having a hard time wrapping my head around where to add this and how to think about it in an idiomatic way. Thanks!

Most Liked

kokolegorille

kokolegorille

Probably something like this…

  @doc false
  def changeset(whatever, attrs) do
    whatever
    |> changeset(attrs)
    |> cast(attrs, @fields)
    |> validate ...
    |> fingerprint()
    |> unique_constraint(:fingerprint, message: "Fingerprint already in use")
  end

  defp fingerprint(changeset) do
    case changeset do
      %Ecto.Changeset{valid?: true, changes: %{address: address}} ->
        put_change(changeset, :fingerprint, create_fingerprint(address))
      _ ->
        changeset
    end
  end

  defp create_fingerprint(address) do
    # Implement your fingerprint here
  end

It is not tested, and fields might not correspond to your structure, but You can get the idea… the 2 last lines from changeset are important.

kokolegorille

kokolegorille

This should not work… as it should be a field

You should use

%Ecto.Changeset{valid?: true, changes: %{street1: street1, street2: street2...}}

# or

%Ecto.Changeset{valid?: true, changes: address}

In the example I gave, whatever is the shemas, and address is just a field of %Whatever{}

You might find ecto changeset structure here. From docs…

changes - The changes from parameters that were approved in casting

kokolegorille

kokolegorille

You might show your schema, and migration file. Be sure :fingerprint field exists, as string…

You might also insert some IO.inspect in your pipeline to show the changeset, like so

  def changeset(whatever, attrs) do
    whatever
    |> changeset(attrs)
    |> cast(attrs, @fields)
    |> validate ...
    |> IO.inspect()
    |> fingerprint()
    |> IO.inspect()
    |> unique_constraint(:fingerprint, message: "Fingerprint already in use")
  end

The function fingerprint take a changeset, and if it is valid, it should persists the change.

If it is clearer, You could have used pattern matching, like so.

defp fingerprint(%Ecto.Changeset{valid?: true, changes: %{address: address}} = changeset) do
  put_change(changeset, :fingerprint, create_fingerprint(address))
end
defp fingerprint(changeset), do: changeset

BTW Try to change the name of the function to generate_fingerprint(), just to be sure it does not conflict with the field name.

Last Post!

fireproofsocks

fireproofsocks OP

Thank you all! I got it working and I learned a lot in the process – inspecting the changeset with IO.inspect() was helpful because I could see the diffs and where fields were being included in or omitted from the changeset. I ran into a bit of trouble because I had set a default value for country, so that would cause that key to be missing from the changeset. Similarly, with the optional “street2” value, if it was sent with a blank value or omitted entirely, the changeset would end up without that field.

Where Next? Top

Trending in Questions Top

stjefim
Hello! Suppose you are building workflow (order / task / payment) processing system with the following requirements: Each workflow con...
New
water
I’m aware of 2 such projects, are there others? git: GitHub - team-alembic/realworld: A fullstack Phoenix LiveView application with back...
New
itzmidinesh
Hi all, I’m working on a Phoenix project where I need to make external HTTP requests and I’m trying to choose between Req and HTTPoison....
New
peck
Hi everyone. My team and I have been working on a fairly modest app based around video streaming and chat, but we’ve landed a customer t...
New
leoschweizer
Hi, we run different LLM models across a cluster, with each node loading a configurable subset. Model-specific queues let nodes consume ...
New
csmr
Hi all, I’m new here and would like to hear peoples views on my Elixir/Phoenix based game-engine! :smiley: Mutonex gamedesign was finish...
New
perzanko
Do we have maintainer of absinthe-graphql/dataloader here? We have a PR that we’d like to merge to the library. Relatively small additive...
New

Other Trending Topics Top

dominicletz
Hey there, I haven’t seen a list of useful Elixir specific skills for the popular AI tools yet so I’m starting one here with my first. ...
New
mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
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
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
OndrejValenta
(I just needed to vent somewhere and LinkedIn is full of hope, or hype, I’m not sure which exactly) AI dream has many faces, but general...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews