dongwooklee96
How to use conditions on creation and destory in Ash
Hi I’m trying to create a simple action to recommend and unrecommend.
For now logic that a person can only recommend one post at a time is implemented using identities.
thumb_up.ex
defmodule Dentallog.DentalLab.ThumbUp do
use Ash.Resource,
data_layer: AshPostgres.DataLayer,
extensions: [
AshGraphql.Resource
]
graphql do
type :dental_lab_post_thumb_up
mutations do
create :thumb_up_dental_lab_post, :thumb_up
destroy :cancel_thumb_up_dental_lab_post, :cancel
end
end
actions do
defaults [:read]
create :thumb_up do
change relate_actor(:user)
end
destroy :cancel do
change relate_actor(:user)
end
end
attributes do
uuid_primary_key :id
create_timestamp :created_at
update_timestamp :updated_at
end
relationships do
belongs_to :user, Dentallog.Accounts.User do
api Dentallog.Accounts
end
belongs_to :dental_lab_post, Dentallog.DentalLab.DentalLabPost do
allow_nil? false
attribute_writable? true
end
end
postgres do
table "dental_lab_thumb_ups"
repo Dentallog.Repo
end
identities do
identity :unique_thumbup, [:dental_lab_post_id, :user_id] do
eager_check_with Dentallog.DentalLab
end
end
end
But I’m not sure what to do about the logic for canceling.
I guess I could use a changeset, but that’s a bit difficult.
Currently, the PK works this: if you enter an ID, it gets deleted.
But I’d like to get the input as the ID of the post and authenticate the user via relate_actor(:user). (post_id, user_id)
Is there a good way to do this?
Also, I’m wondering if you recommend using identities or atomic to allow for guarantee one-time recommendations.
Marked As Solved
zachdaniel
You can do that with bulk destroy actions. We will be working on guides that explain how to use bulk actions more than what exists currently. But you can do this:
read :my_thumb_ups do
filter expr(id == ^actor(:id))
end
ThumbUp
|> Ash.Query.for_read(:my_thumb_ups, %{}, actor: actor)
|> Ash.Query.filter(dental_lab_post.id == ^post_id)
|> ThumbUp.bulk_destroy!(:destroy)
You can put this behind a generic action:
action :remove, :atom do
constraints one_of: [:ok]
argument :post_id, :uuid, allow_nil?: false
run fn input, context ->
ThumbUp
|> Ash.Query.for_read(:my_thumb_ups, %{}, Ash.context_to_opts(context))
|> Ash.Query.filter(dental_lab_post.id == ^input.post_id)
|> ThumbUp.bulk_destroy!(:destroy)
{:ok, :ok}
end
end
And then you can put that in your code_interface:
code_interface do
define_for YourApi
define :remove, args: [:post_id]
end
Then you can call it:
ThumbUp.remove!(post.id)
Also Liked
FlyingNoodle
This is only tangentially related to your original question but I would recommend that you do in fact return the deleted post. This way you can automagically update your client cache (if you are using apollo as an example):
mutation myDeleteMutation($id: ID!) {
deleteSomething(id: $id) {
id
author {
id
posts {
id // <- this line here will tell apollo to remove the post from the list of posts in the authors cache
}
}
}
}
this way you dont have to do manual cache manipulations. Obviously this doesn’t really scale to thousands of rows. But for things where the total number of rows will always remain small this works really nicely.
zachdaniel
Ah, okay, I see the problem.
zachdaniel
I’ve fixed the issue in main, but I’d suggest changing your action in such a way that it will be better anyway, and will avoid the issue. If you make your action return the id of the post that was deleted
action :remove, :string do
argument :post_id, :uuid, allow_nil?: false
run fn input, context ->
ThumbUp
|> Ash.Query.for_read(:my_thumb_ups, %{}, Ash.context_to_opts(context))
|> Ash.Query.filter(dental_lab_post.id == ^input.post_id)
|> ThumbUp.bulk_destroy!(:destroy)
{:ok, input.post_id}
end
it should work ![]()
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance










