robpallotta

robpallotta

If you define a belongs_to relationship with allow_nil? true, the default create action becomes unusable; any attempt to use it will fail because the relationship’s attribute is not set.

Consider the following resource with a belongs_to relationship:

defmodule Helpdesk.Support.Ticket do
  use Ash.Resource

  actions do
    defaults [:create, :read, :update, :destroy]
  end

  attributes do
    uuid_primary_key :id

    attribute :subject, :string
  end

  relationships do
    belongs_to :representative, Helpdesk.Support.Representative do
      allow_nil? false
    end
  end
end

One would assume that this would allow the user to create a Ticket by passing a Representative in the input to the create action, like:

Helpdesk.Support.Ticket |> Ash.Changeset.for_create(:create, %{representative: rep}) |> Helpdesk.Support.create!()

But this raises an error that “relationship representative is required”, despite it being provided.

To add to the confusion, this is inconsistent with the behaviour in other situations. For example Ash.Seed.seed!(%Helpdesk.Support.Ticket{representative: rep}) will create the Ticket record as expected, with the relationship attribute inferred correctly. Or if Representative had an update action to create an associated Ticket:

defmodule Helpdesk.Support.Representative do
  use Ash.Resource,
    data_layer: Ash.DataLayer.Ets

  actions do
    defaults [:create, :read, :update, :destroy]

    update :add_ticket do
      argument :subject, :string
      change manage_relationship(:subject, :tickets, value_is_key: :subject, type: :create)
    end
  end

  attributes do
    uuid_primary_key :id
    attribute :name, :string
  end

  relationships do
    has_many :tickets, Helpdesk.Support.Ticket
  end
end

Calling the add_ticket action on a Representative will successfully create a new related Ticket:

rep |> Ash.Changeset.for_update(:add_ticket, %{subject: "blah blah"}) |> Helpdesk.Support.update!()
#Helpdesk.Support.Representative<
  tickets: [
    #Helpdesk.Support.Ticket<
      representative: #Ash.NotLoaded<:relationship, field: :representative>,
      __meta__: #Ecto.Schema.Metadata<:built, "">,
      id: "f403066a-cf0e-43f8-a3f4-b40fac8a7d27",
      subject: "blah blah",
      representative_id: "bd0e5d0b-5903-4083-ab9f-3fb42790e220",
      aggregates: %{},
      calculations: %{},
      ...
    >
  ],
  __meta__: #Ecto.Schema.Metadata<:loaded>,
  id: "bd0e5d0b-5903-4083-ab9f-3fb42790e220",
  name: "test",
  aggregates: %{},
  calculations: %{},
  ...
>

This is doubly confusing because the add_ticket update action uses Ticket’s default create action to create the new related Ticket, but in a way that user’s seemingly are not.

I know there are ways to get this to work, either by making the relationship attribute_writable? true and passing the associated ID directly or by defining a custom create action that uses manage_relationship, but neither of those are intuitive solutions. I think the default create action should be able to handle passing the related record as part of the input without needing any extra code.

This is using ash version 2.19.9.

Showing Posts 1 to 1

barnabasJ

barnabasJ

Ash Core Team

This is caused by the default of attribute_writable? being false. IIRC this will change to true in 3.0 and make this more intuitive to the user.

Although, this would only allow you to pass in the represenative_id, not the whole representative record by default.

— All posts loaded —

Where Next? Top

Trending in Discussions Top

AstonJ
As the title says, please share what you’ve been up to with Elixir. Whether that’s been learning it, looking into it, making stuff with i...
2977 94592 917
New
cblavier
Hey there, It’s been more than a year since we started using LiveView as our main UI library and building a whole library of UI componen...
New
heathen
Quite interesting article Google brought me. Didn’t find any mentions about it here. What do you think in general? Would you use togethe...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
AstonJ
Since we have deprecated our Erlang sections (as we have dedicated Erlang Forums now) let’s add this thread for those who’d like to post ...
New
Null-logic-0
What IDE or editor are you using for Elixir development? Personally, I use Zed, and I really like it, but sometimes I wish there were a ...
New
maennchen
:warning: Security advisory: Decimal DoS vulnerability A vulnerability has been published for decimal where very large exponents can cau...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews