dongwooklee96

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

zachdaniel

Creator of Ash

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

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

zachdaniel

Creator of Ash

Ah, okay, I see the problem.

zachdaniel

zachdaniel

Creator of Ash

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 :slight_smile:

Where Next?

Popular in Questions Top

_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
beno
I will often find my self writing things similar to: case some_value do nil -&gt; something() "" -&gt; something() _ -&gt; somethi...
New
mgjohns61585
Could someone help me? I’m making my first elixir program, number guessing game. I can’t figure out how to convert the user’s guess from ...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
vegabook
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New

Other popular topics Top

danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 29603 241
New
Nvim
Anybody knows a comprehensive comparison of Django and Phoenix, thanks for the help. Where are they similar? Where do they differ the m...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New
KronicDeth
Elixir plugin for JetBrain’s IntelliJ Platform (including Rubymine) This is a plugin that adds support for Elixir to JetBrains IntelliJ...
289 36352 110
New

Latest on Elixir Forum

We're in Beta

About us Mission Statement