Soft-delete and cast_assoc

Hello everyone! :wave:

Given the following 2 schemas:

defmodule Company do
  use Ecto.Schema
  import Ecto.Changeset

  schema "companies" do
    field :name, :string
    field :country_code, :string, default: "NO" # ISO 3166 alpha-2 code
    field :org_number, :string

    timestamps()

    has_many :departments, Department
  end

  def changeset(%Company{} = company, attrs \\ %{}) do
    company
    |> cast(attrs, [:name, :country_code, :org_number])
    |> cast_assoc(:departments)
  end
end

defmodule Department do
  use Ecto.Schema
  import Ecto.Changeset

  schema "departments" do
    field :name, :string
    field :deleted_at, Timex.Ecto.DateTime

    timestamps()

    belongs_to :company, Company
  end

  def changeset(%Department{} = department, attrs \\ %{}) do
    department
    |> cast(attrs, [:company_id, :name])
    |> validate_required([:name])
  end

  def delete_changeset(%Department{} = department) do
    change(department, %{deleted_at: Timex.now()})
  end
end

I’m using cast_assoc for has_many assoc on company, and I’d like to define :on_replace in such a way that I could do soft-delete with Department.delete_changeset |> Repo.update. Can this be done?

I was thinking about altering department changeset action from :delete to :update in such case, but when setting on_replace: :delete in company’s assoc it does straight Repo.delete without passing department through my department’s changeset fn.

What would be the best way to combine soft-delete (by setting deleted_at) with cast_assoc?

2 Likes

Did you ever come up w/ a solution to this? Interested in a nice pattern for the same problem…