Is it possible chain read actions Ash

I am trying to DRY my resources. Some actions share logic partially. For example, the following two actions share the same logic except filter by department id.

How can I chain action or call an action inside another action?

    read :active do
      description "Gets ongoing and future time off requests"
      filter expr(status == :approved)
      filter expr((starts_at <= today() && ends_at >= today()) || starts_at > today())
    end

    read :active_by_department do
      description "Gets ongoing and future time off requests by department"
      argument :department_id, :uuid
      filter expr(person.department_id == ^arg(:department_id))
      
      # Repetitive code
      filter expr(status == :approved)
      filter expr((starts_at <= today() && ends_at >= today()) || starts_at > today())
    end

You can’t “chain” them but you can create a single preparation that contains the logic for each. And then use

prepare Prepararion1
prepare Preparation2
1 Like

Thanks. This worked for me. Below is the answer for someone who might be looking for the same solution in the future.

I extracted the logic into its own preparation

Final results

    # What name should I give this action?
    read :active do
      description "Gets ongoing and future time off requests"
      prepare MyApp.Leaves.LeaveRequest.Preparations.FilterActive
    end

    read :active_by_department do
      description "Gets ongoing and future time off requests by department"
      argument :department_id, :uuid
      filter expr(person.department_id == ^arg(:department_id))
      prepare MyApp.Leaves.LeaveRequest.Preparations.FilterActive
    end

Preparation implementation

defmodule MyApp.Leaves.LeaveRequest.Preparations.FilterActive do
  use Ash.Resource.Preparation

  def prepare(query, _opts, _context) do
    query
    |> Ash.Query.filter((starts_at <= today() && ends_at >= today()) || starts_at > today())
    |> Ash.Query.filter(status == :approved)
  end
end
4 Likes