How to define ecto singleton instance

I have a brand schema like so

defmodule Example.App.Brand do
  use Example.Schema
  import Ecto.Changeset

  schema "brands" do
    field :brand_color, :string
    field :brand_logo, :string

    timestamps()
  end

  def changeset(brand, attrs) do
    brand
    |> cast(attrs, [:brand_color, :brand_logo])
    |> validate_required([:brand_color, :brand_logo])
  end
end

I want this schema to be a singleton, so I need to override a value which is already saved with a new value, my update function is standard and I’m doing my update trough the changeset

 def update_brand(user, attrs) do
    %Brand{}
    |> Brand.changeset(attrs)
    |> Repo.insert
  end

so how can I ensure that I’m overriding the current data and not just creating a new one?

Hard-code the id to 1? :slight_smile:

Could also write a database constraint that asserts there are no other rows in that table.

You could have a function that takes attributes and updates a record if it exists or create a new record if there are none.

For example:

def get_brand(), do: Repo.one(Brand)

def create_brand(attrs), do: Brand.changeset(%Brand{}, attrs) |> Repo.insert()

def update_brand(brand, attrs), do: Brand.changeset(brand, attrs) |> Repo.update()

def change_brand(attrs) do
  case get_brand() do
    nil -> create_brand(attrs)
    brand -> update_brand(brand, attrs)
  end
end
3 Likes

Yes, exactly what I want, thanks for the example, will play with that

Ecto also has an insert_or_update function if you like https://hexdocs.pm/ecto/Ecto.Repo.html#c:insert_or_update/2

I typically have an upsert function for this sort of thing.

def upsert_brand(attrs) do
  case get_brand() do
    nil -> %Brand{}
    brand -> brand
  end
  |> Brand.changeset(attrs)
  |> Repo.insert_or_update()
end
4 Likes