Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Ash: 8 - Relationships

ash_tutorial/relationships.livemd

Ash: 8 - Relationships

Application.put_env(:ash, :validate_domain_resource_inclusion?, false)
Application.put_env(:ash, :validate_domain_config_inclusion?, false)
Mix.install([{:ash, "~> 3.0"}], consolidate_protocols: false)

Relationships

Customizing Actions HomeCode Interfaces

In this tutorial you will create a relationship between a Ticket and Representative resource

Create a relationships do .. end block in the Ticket resource.

Inside the relationships block, define a belongs_to representative like so:

belongs_to :representative, Tutorial.Support.Representative

Show Solution

  defmodule Tutorial.Support.Ticket do

  # ...

    relationships do
      # belongs_to means that the destination attribute is unique, meaning only one related record could exist.
      # We assume that the destination attribute is `representative_id` based
      # on the name of this relationship and that the source attribute is `representative_id`.
      # We create `representative_id` automatically.
      belongs_to :representative, Tutorial.Support.Representative
    end

  # ...

Enter your solution

defmodule Tutorial.Support.Ticket do
  use Ash.Resource,
    domain: Tutorial.Support,
    data_layer: Ash.DataLayer.Ets

  actions do
    defaults [:read]

    create :create do
      accept [:subject, :description, :status, :representative_id]
    end
  end

  attributes do
    uuid_primary_key :id
    attribute :subject, :string, allow_nil?: false
    attribute :description, :string

    attribute :status, :atom do
      constraints one_of: [:open, :closed]
      default :open
      allow_nil? false
    end

    create_timestamp :created_at
    update_timestamp :updated_at
  end

  # <-- Add the relationship here
  relationships do
    belongs_to :representative, Tutorial.Support.Representative
  end
end

defmodule Tutorial.Support.Representative do
  use Ash.Resource,
    domain: Tutorial.Support,
    data_layer: Ash.DataLayer.Ets

  actions do
    defaults [:read]

    create :create do
      accept [:name]
    end
  end

  attributes do
    uuid_primary_key(:id)
    attribute(:name, :string)
  end
end
defmodule Tutorial.Support do
  use Ash.Domain

  resources do
    resource Tutorial.Support.Ticket
    resource Tutorial.Support.Representative
  end
end

Creating a Ticket record with a representative Relationship

First, create the representative Joe.

# Creates a Representative
joe =
  Tutorial.Support.Representative
  |> Ash.Changeset.for_create(:create, %{name: "Joe Armstrong"})
  |> Ash.create!()

Next up, create a ticket and assign the representative Joe to the ticket.

# Creates a Ticket with the representative
Tutorial.Support.Ticket
|> Ash.Changeset.for_create(:create, %{subject: "My spoon is too big!", representative_id: joe.id})
|> Ash.create!()
# `load!/2` loads in the representative. Try removing this line to see what changes
#|> Ash.load!([:representative])

As you can see it didn’t quite work. The representative_id is not accepted by the create action on Tutorial.Support.Ticket. If you add :representative_id to that list, and try again you should now see that the representative was correctly assigned.

Customizing Actions HomeCode Interfaces