add ash_tutorial
This commit is contained in:
163
ash_tutorial/relationships.livemd
Normal file
163
ash_tutorial/relationships.livemd
Normal file
@@ -0,0 +1,163 @@
|
||||
# Ash: 6 - Relationships
|
||||
|
||||
```elixir
|
||||
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
|
||||
|
||||
<div class="flex items-center w-full flex-start justify-between rounded-xl p-4" style="background-color: #f0f5f9; color: #61758a;">
|
||||
<div class="flex">
|
||||
<i class="ri-arrow-left-fill"></i>
|
||||
<a class="flex ml-2" style="color: #61758a;" href="customizing_actions.livemd">Customizing Actions</a>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<i class="ri-home-fill"></i>
|
||||
<a class="flex ml-2" style="color: #61758a;" href="overview.livemd">Home</a>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<a class="flex mr-2" style="color: #61758a;" href="code_interfaces.livemd">Code Interfaces</a>
|
||||
<i class="ri-arrow-right-fill"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
### 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`
|
||||
|
||||
<details class="rounded-lg my-4" style="background-color: #96ef86; color: #040604;">
|
||||
<summary class="cursor-pointer font-bold p-4"></i>Show Solution</summary>
|
||||
<div class="p-4">
|
||||
|
||||
```elixir
|
||||
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
|
||||
|
||||
# ...
|
||||
```
|
||||
|
||||
</div>
|
||||
</details>
|
||||
|
||||
### Enter your solution
|
||||
|
||||
```elixir
|
||||
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
|
||||
|
||||
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
|
||||
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
|
||||
```
|
||||
|
||||
```elixir
|
||||
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.
|
||||
|
||||
```elixir
|
||||
# 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.
|
||||
|
||||
```elixir
|
||||
# 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.
|
||||
|
||||
<!-- livebook:{"break_markdown":true} -->
|
||||
|
||||
<div class="flex items-center w-full flex-start justify-between rounded-xl p-4" style="background-color: #f0f5f9; color: #61758a;">
|
||||
<div class="flex">
|
||||
<i class="ri-arrow-left-fill"></i>
|
||||
<a class="flex ml-2" style="color: #61758a;" href="customizing_actions.livemd">Customizing Actions</a>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<i class="ri-home-fill"></i>
|
||||
<a class="flex ml-2" style="color: #61758a;" href="overview.livemd">Home</a>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<a class="flex mr-2" style="color: #61758a;" href="code_interfaces.livemd">Code Interfaces</a>
|
||||
<i class="ri-arrow-right-fill"></i>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user