Ash: 6 - Attributes
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)
Attributes
Querying HomeCustomizing ActionsIn this tutorial you will add and configure Attributes to a Ticket resource
The Ticket resource will represent a helpdesk ticket.
It will have 3 main attributes.
-
A
subject
or title -
A
description
-
A
status
which can be either:open
or:closed
It will also have 2 attributes for keeping track of when the ticket was created, and when it was last updated.
Subject
You need to make sure the subject
is always set, it’s not possible to create a ticket without a subject. You can do this by setting allow_nil?
to false
. Like so: attribute :subject, :string, allow_nil?: false
Description
The :description
is simple, it’s a :string
and it is allowed to be empty.
Status
:status
is more complicated.
-
It is of the type
:atom
-
It can only be the value
:open
or:closed
-
By default it is
:open
-
And it can’t be
nil
Attributes are set in a do end
block like so:
attribute :status, :atom do
# ...
allow_nil? false
end
To set a constraint of values, you can use the constraints
option, like so:
constraints [one_of: [:open, :closed]]
To set the default value, you use default :open
.
Keeping track of Created and Updated
Ash provides create_timestamp and update_timestamp to keep track of when the Resource was first created, and when it was last updated.
Add the following to the attributes block:
create_timestamp :created_at
update_timestamp :updated_at
Show 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]
end
end
attributes do
uuid_primary_key :id
attribute :subject, :string, allow_nil?: false
attribute :description, :string
# status is either `open` or `closed`.
attribute :status, :atom do
# Constraints allow you to provide extra rules for the value.
# The available constraints depend on the type
# See the documentation for each type to know what constraints are available
# Since atoms are generally only used when we know all of the values
# it provides a `one_of` constraint, that only allows those values
constraints [one_of: [:open, :closed]]
default :open
allow_nil? false
end
create_timestamp :created_at
update_timestamp :updated_at
end
end
defmodule Tutorial.Support do
use Ash.Domain
resources do
resource Tutorial.Support.Ticket
end
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]
end
end
attributes do
uuid_primary_key :id
# Add the attributes here -->
# - Subject
attribute :subject, :string, allow_nil?: false
# - Description
attribute :description, :string
# - Status
attribute :status, :atom do
constraints [one_of: [:open, :closed]]
default :open
allow_nil? :false
end
# - Create Timestamp
create_timestamp :created_at
# - Update Timestamp
update_timestamp :updated_at
end
end
defmodule Tutorial.Support do
use Ash.Domain
resources do
resource Tutorial.Support.Ticket
end
end
Creating a Ticket
Create a Ticket
without any attributes.
Remember, when creating a resource use a changeset (Ash.Changeset.for_create/3
), which gets passed to Ash.create!/1
.
The output should look something like this:
** (Ash.Error.Invalid) Input Invalid
* attribute subject is required
Show Solution
Tutorial.Support.Ticket
|> Ash.Changeset.for_create(:create, %{})
|> Ash.create!()
Tutorial.Support.Ticket
|> Ash.Changeset.for_create(:create, %{})
|> Ash.create!()
Now create a Ticket with a subject
Show Solution
Tutorial.Support.Ticket
|> Ash.Changeset.for_create(:create, %{subject: "This is the subject"})
|> Ash.create!()
Tutorial.Support.Ticket
|> Ash.Changeset.for_create(:create, %{subject: "subject one"})
|> Ash.create!()
Now create a ticket with the status
set to :closed
Show Solution
Tutorial.Support.Ticket
|> Ash.Changeset.for_create(:create, %{subject: "This is the subject", status: :closed})
|> Ash.create!()
Tutorial.Support.Ticket
|> Ash.Changeset.for_create(:create, %{subject: "subject two", status: :closed})
|> Ash.create!()
Now try creating a ticket with the status set to :pending
. This should give an error because :pending
is not a valid status
.
Show Solution
Tutorial.Support.Ticket
|> Ash.Changeset.for_create(:create, %{subject: "This is the subject", status: :pending})
|> Ash.create!()
Tutorial.Support.Ticket
|> Ash.Changeset.for_create(:create, %{subject: "subject three", status: :pending})
|> Ash.create!()
Latest created Ticket
Since you added a creation date, you can now query on the latest created ticket.
First, sort using the Ash.Query.sort/2
function by Ash.Query.sort(created_at: :desc)
Then limit the amount of records with the Ash.Query.limit/2
function by doing Ash.Query.limit(1)
Finally call Ash.read_one!()
on the query.
Hint: Use a pipeline
Show Solution
Tutorial.Support.Ticket
|> Ash.Query.sort(created_at: :desc)
|> Ash.Query.limit(1)
|> Ash.read_one!()
Tutorial.Support.Ticket
|> Ash.Query.sort(created_at: :desc)
|> Ash.Query.limit(1)
|> Ash.read_one!()
Querying
HomeCustomizing Actions