script

script

I am testing my endpoint to delete a record. It works fine if record doesn’t have any child associations.

This is the code:

       def delete(conn, %{"id" => id}) do
         record = get_record(id)

          case Repo.delete(record) do
            {:ok, struct} ->
               send_resp(conn, :no_content, "Record deleted")

          {:error, reason} ->
           conn
             |> put_status(422)
             |> render(Admin.ErrorView, "error.json",
               code: 422,
              message: "Error occurred",
              errors: reason
             )
         end
       end

  def get_record(id) do
    case Repo.get(model, id) do
      nil ->
        render(Admin.ErrorView, "error.json", code: 404, message: "Record not found")

      record ->
        record
    end
  end

But I want to send the proper error message if the record has some relationship with some other records. It returns the internal server error . and not the foreign key error.

Any suggestions?

Thanks

Showing Posts 1 to 8

kokolegorille

kokolegorille

You might use foreign key constraint.

The relevant code should be something like this …

your_record
|> Ecto.Changeset.change()
|> foreign_key_constraint(:your_assocs, name: :your_assocs_your_record_id_fkey, message: "still exist")
script

script OP

Thanks for your suggestion.This foreign key constraint works if we want to create or update child and its parents doesn’t exist. What I want is other way around, Like if we delete a parent. I thought {:error, reason} should throw an error about foreign key but gives server error.

kokolegorille

kokolegorille

Well, the example is from Programming Phoenix 1.4, and it is for solving the exact same problem, to put a constraint on the parent, not to be able to delete it if there is still children :slight_smile:

PS. You should note the plural and singular form…

In the book, it’s for category, with many videos.

aseigo

aseigo

Have you tried getting a full backtrace? Or can you post what exact error phoenix is generating?

One thing that pops out to me is that Ecto.Repo.delete returns a changeset in the error tuple on failure.. so the reason in {:error, reason} is a changeset rather than, say, a simple string. So if your template is expecting reason to be a plain renderable string, it probably isn’t :wink:

Also, it is possible under certain circumstances (e.g. missing table fields, such as from a typo) for an exception to be thrown and that won’t be caught by your case statement…

Hard to know without seeing more of the code though..

kokolegorille

kokolegorille

I made an example with nodes and leafs

  schema "nodes" do
    field(:name, :string)
    has_many(:leafs, Leaf)
    timestamps()
  end

...
  schema "leafs" do
    field(:name, :string)
    belongs_to(:node, Node)
    timestamps()
  end

I load a node, with leafs…

iex> import Ecto.Changeset
iex> n = EctoLab.Fk.get_node(1) |> EctoLab.Repo.preload(:leafs)
%EctoLab.Fk.Node{
  __meta__: #Ecto.Schema.Metadata<:loaded, "nodes">,
  id: 1,
  inserted_at: ~N[2018-09-06 12:41:43.978124],
  leafs: [
    %EctoLab.Fk.Leaf{
      __meta__: #Ecto.Schema.Metadata<:loaded, "leafs">,
      id: 2,
      inserted_at: ~N[2018-09-06 12:53:11.336298],
      name: "lolo", 
      node: #Ecto.Association.NotLoaded<association :node is not loaded>,
      node_id: 1,
      updated_at: ~N[2018-09-06 12:53:11.336308]
    }
  ],
  name: "koko",
  updated_at: ~N[2018-09-06 12:41:43.979841]
}

And here, if I try to delete the node

iex> changeset = Ecto.Changeset.change(n)
iex> changeset = foreign_key_constraint(changeset, :leafs, name: :leafs_node_id_fkey, message: "still exist") 
#Ecto.Changeset<action: nil, changes: %{}, errors: [], data: #EctoLab.Fk.Node<>,
 valid?: true>
iex(30)> EctoLab.Repo.delete(changeset)

14:59:08.942 [debug] QUERY OK db=0.1ms
begin []
 
14:59:08.949 [debug] QUERY ERROR db=6.4ms
DELETE FROM "nodes" WHERE "id" = $1 [1]
 
14:59:08.949 [debug] QUERY OK db=0.2ms
rollback []
{:error,
 #Ecto.Changeset<
   action: :delete,
   changes: %{},
   errors: [leafs: {"still exist", []}],
   data: #EctoLab.Fk.Node<>,
   valid?: false
 >}

I cannot delete it, because it has leafs, and I got the message in the changeset.

belaustegui

belaustegui

This is the proper solution. You can also use Ecto.Changeset.no_assoc_constraint which, as stated in the docs:

This is similar to foreign_key_constraint/3 except that the field is inferred from the association definition. This is useful to guarantee that parent can only be deleted (or have its primary key changed) if no child exists in the database. Therefore, it only applies to has_* associations.

script

script OP

Thanks

script

script OP

Appreciate your help.

— All posts loaded —

Where Next? Top

Trending in Questions Top

stjefim
Hello! Suppose you are building workflow (order / task / payment) processing system with the following requirements: Each workflow con...
New
water
I’m aware of 2 such projects, are there others? git: GitHub - team-alembic/realworld: A fullstack Phoenix LiveView application with back...
New
peck
Hi everyone. My team and I have been working on a fairly modest app based around video streaming and chat, but we’ve landed a customer t...
New
bradley
I really like the adapter patterns that ecto, nebulex, waffle, etc. use and would love find something similar for a key management servic...
New
unaware8150
Hello folks! So at work, we are seeing some situations where we have to define some “fixed” strings that are used across the codebase in...
New
Alvinkariuki
How Can I Optimise Compile Time Dependencies I have been building an elixir application for about 2 years now. Many modules and files ha...
New
leoschweizer
Hi, we run different LLM models across a cluster, with each node loading a configurable subset. Model-specific queues let nodes consume ...
New

Other Trending Topics Top

mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
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
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
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
budgie
I love Elixir. It’s one of 2 programming languages I’ve ever fallen in love with. But I don’t use it anymore. Serverless was the promis...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews