Ash: 10 - Code Interfaces
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)
Code Interfaces
Relationships HomeAggregatesIn this tutorial you will add a Code Interface
In previous tutorials you always used Changesets
directly to CRUD on resources.
While this is a perfectly valid way of handling CRUD operations, Ash provides Code Interfaces to make this more ergonomic for you.
The code interface can be defined on the resources or the domain. In this example, we will define it on the domain.
You will add 3 code interfaces for:
- Creating a representative
- Opening a ticket
- Assigning a representative
For each resource you want to add a code interface to, inside that resource definition on the domain, you will place “definitions”. For example:
resource MyApp.Tweet do
define :create_tweet, args: [:content]
end
Then add the 3 interfaces by defining the following inside the Ticket
resource’s block:
-
define :assign_ticket, args: [:representative_id], action: :assign
-
define :open_ticket, args: [:subject, :description], action: :open
And the following inside the Representative
resource’s block.
-
define :create_representative, args: [:name], action: :create
Show Solution
resource Tutorial.Support.Ticket do define :assign_ticket, args: [:representative_id], action: :assign define :open_ticket, args: [:subject, :description], action: :open end resource Tutorial.Support.Representative do define :create_representative, args: [:name], action: :create 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 :open do
accept [:subject, :description]
end
update :close do
change set_attribute(:status, :closed)
end
update :assign do
accept [:representative_id]
end
end
attributes do
uuid_primary_key :id
attribute :subject, :string, allow_nil?: false
attribute :description, :string, allow_nil?: true
attribute :status, :atom do
constraints one_of: [:open, :closed]
default :open
allow_nil? false
end
create_timestamp :created_at
update_timestamp :updated_at
end
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 do
define :assign_ticket, args: [:representative_id], action: :assign
define :open_ticket, args: [:subject, :description], action: :open
end
resource Tutorial.Support.Representative do
define :create_representative, args: [:name], action: :create
end
end
end
Using the Code Interfaces
Create a Representative, but instead of using a changeset, use the code interface you created.
You can use a code interface by calling Tutorial.Support.create_representative!/1
with the desired name.
Set the name to Joe Armstrong
and store it in a joe
variable.
Show Solution
joe = Tutorial.Support.create_representative!("Joe Armstrong")
joe = Tutorial.Support.create_representative!("Joe Armstrong")
Create a Ticket with the created code interface.
Call Tutorial.Support.open_ticket!/2
with a subject
and description
and store the result in a ticket
variable.
Show Solution
ticket = Tutorial.Support.open_ticket!("I can't find my hand!", "I think someone stole it.")
ticket = Tutorial.Support.open_ticket!("The subject", "the description")
Assign the Representative joe
to the Ticket using the code Interface.
Use Tutorial.Support.assign_ticket!/2
.
Show Solution
Tutorial.Support.assign_ticket!(ticket, joe.id)
Tutorial.Support.assign_ticket!(ticket, joe.id)
Managing Relationships
HomeAggregates