Ash: 4 - 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 an Issue resource
The Issue
resource will represent a GitHub-style issue in BitHub.
It will have 3 main attributes:
-
A
title
that serves as the issue’s subject -
A
body
containing the issue description -
A
state
which can be either:open
or:closed
It will also have 2 attributes for keeping track of when the issue was created and when it was last updated.
Title
The title
is required; an issue cannot be created without a title.
You can enforce this by setting allow_nil?
to false
, like so:
attribute :title, :string, allow_nil?: false
Body
The body
is optional and can be left empty. It is simply a :string
type.
State
:state
is more structured:
-
It is of type
:atom
-
It can only have the values
:open
or:closed
-
By default, it is
:open
-
It cannot be
nil
Attributes are set within a do end
block like so:
attribute :state, :atom do
# Constraints ensure only valid values can be used.
constraints [one_of: [:open, :closed]]
default :open
allow_nil? false
end
Keeping track of Created and Updated timestamps
Ash provides create_timestamp and update_timestamp to track when the resource was first created and when it was last updated.
To add this, include the following in the attributes block:
create_timestamp :created_at
update_timestamp :updated_at
Show Solution
defmodule BitHub.Issues.Issue do
use Ash.Resource,
domain: BitHub.Issues,
data_layer: Ash.DataLayer.Ets
actions do
defaults [:read]
create :create do
accept [:title, :body, :state]
end
end
attributes do
uuid_primary_key :id
attribute :title, :string, allow_nil?: false
attribute :body, :string
# State is either `open` or `closed`
attribute :state, :atom do
constraints [one_of: [:open, :closed]]
default :open
allow_nil? false
end
create_timestamp :created_at
update_timestamp :updated_at
end
end
defmodule BitHub.Issues do
use Ash.Domain
resources do
resource BitHub.Issues.Issue
end
end
defmodule BitHub.Issues.Issue do
use Ash.Resource,
domain: BitHub.Issues,
data_layer: Ash.DataLayer.Ets
actions do
defaults [:read]
create :create do
accept [:title, :body, :state]
end
end
attributes do
uuid_primary_key :id
# Define the main attributes for an issue
attribute :title, :string, allow_nil?: false
attribute :body, :string
attribute :state, :atom do
constraints [one_of: [:open, :closed]]
default :open
allow_nil? false
end
create_timestamp :created_at
update_timestamp :updated_at
end
end
defmodule BitHub.Issues do
use Ash.Domain
resources do
resource BitHub.Issues.Issue
end
end
Creating an Issue
We are going to create an Issue
without any attributes. This will show an error.
Remember, when creating a resource use a changeset (Ash.Changeset.for_create/3
), which gets passed to Ash.create!/1
.
The error output will look like this:
** (Ash.Error.Invalid) Bread Crumbs: > Error returned from: BitHub.Issues.Issue.create Invalid Error * attribute title is required (ash 3.4.54) lib/ash/error/changes/required.ex:4:
It will show the Ash version and line number. Don't be afraid to look at the source code.
Show Solution
BitHub.Issues.Issue
|> Ash.Changeset.for_create(:create, %{})
|> Ash.create!()
BitHub.Issues.Issue
|> Ash.Changeset.for_create(:create, %{})
|> Ash.create!()
Now create an Issue
with a title
Show Solution
BitHub.Issues.Issue
|> Ash.Changeset.for_create(:create, %{title: "This is the title"})
|> Ash.create!()
BitHub.Issues.Issue
|> Ash.Changeset.for_create(:create, %{title: "This is the title"})
|> Ash.create!()
Now create an Issue with the state
set to :closed
Show Solution
BitHub.Issues.Issue
|> Ash.Changeset.for_create(:create, %{title: "This is the title", state: :closed})
|> Ash.create!()
BitHub.Issues.Issue
|> Ash.Changeset.for_create(:create, %{title: "This is the title", state: :closed})
|> Ash.create!()
Latest created Issue
Since you added a creation date, you can now query on the latest created Issue.
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
BitHub.Issues.Issue
|> Ash.Query.sort(created_at: :desc)
|> Ash.Query.limit(1)
|> Ash.read_one!()
BitHub.Issues.Issue
|> Ash.Query.sort(created_at: :desc)
|> Ash.Query.limit(1)
|> Ash.read_one!()
Querying
HomeCustomizing Actions