How to display no_assoc_constraint message in error flash?

I am trying to display the no_assoc_constraint message in a flash i.e when a website has blogs it errors

how do I access the message in the no_assoc_contraint in from the error

delete from context

  def delete_website(%Website{} = website) do
    website
    |> Ecto.Changeset.change
    |> Ecto.Changeset.no_assoc_constraint(:blogs, message: "error 1 blogs exist")
    |> Ecto.Changeset.no_assoc_constraint(:posts, message: "error 2 posts exist")
    |> Repo.delete
  end

delete in controller

def delete(conn, %{"id" => id}, user) do
    website = Repo.get!(user_websites(user), id)
              |> Repo.preload(:user)

    case Websites.delete_website(website) do
      {:ok, _website} ->
        conn
        |> put_flash(:info, "Website deleted successfully.")
        |> redirect(to: Routes.website_path(conn, :index))

      {:error, %Ecto.Changeset{} = changeset} ->
        conn
        |> put_flash(:error, "Website delete issues: existing blogs or posts")
        |> redirect(to: Routes.website_path(conn, :index))
    end
  end

Ideally I want to put the message from no_assoc_constraint in the flash i.e. Website delete issues: existing blogs or posts becomes error 1 blogs exist

Hi,

You can pattern match on the error and use it in the flash:


 case Websites.delete_website(website) do
      {:ok, _website} ->
        conn
        |> put_flash(:info, "Website deleted successfully.")
        |> redirect(to: Routes.website_path(conn, :index))

      {:error, %{ errors: errors } = changeset} ->
       
        msg = handle_error(errors)

        conn
        |> put_flash(:error, msg)
        |> redirect(to: Routes.website_path(conn, :index))
    end

You can then match to the :key of the error you are looking for:

defp handle_error({:key, { messge, _ }}), do: message

Remember you will need a catch all.

2 Likes

hello and thank-you @andrewb

I am not sure what you mean by the catchall

I add this

  def delete(conn, %{"id" => id}, user) do
    website = Repo.get!(user_websites(user), id)
              |> Repo.preload(:user)

    case Websites.delete_website(website) do
      {:ok, _website} ->
        conn
        |> put_flash(:info, "Website deleted successfully.")
        |> redirect(to: Routes.website_path(conn, :index))

      {:error, %{ errors: errors } = changeset} ->
       
        msg = handle_error(errors)

        conn
        |> put_flash(:error, msg)
        |> redirect(to: Routes.website_path(conn, :index))
    end

  end

  defp handle_error({:key, { message, _ }}), do: message

and get

no function clause matching in WebsiteController.handle_error/1

Called with 1 arguments

  1. [blogs: {“blogs exist”, [constraint: :no_assoc, constraint_name: “blogs_blogs_website_id_fkey”]}]

Attempted function clauses (showing 1 out of 1)

defp handle_error( {:key, {message, _}} )

Hi,

in the handle_error you need to replace the :key with the :key for the error message you want to extract. The reference to catch all is that you need to handle any calls that don’t match on keys.

defp handle_error({PUT_YOUR_KEY_HERE, { message, _ }}), do: message

Then have have something like:

defp handle_error({all_errors, { _, _ }}), do: "Something went wrong!"

If you are not sure what the error :key is you can IO.inspect(changeset) and then cause the error.

Hope this helps.

Andrew

PS: I am doing this from memory … post again if you can’t work it out

thanks, yes, it very much helps

IO.inspect is giving me this

 #Ecto.Changeset<
   action: :delete,
   changes: %{},
   errors: [
     blogs: {"blogs exist",
      [constraint: :no_assoc, constraint_name: "blogs_blogs_website_id_fkey"]}
   ],
   data: #Websites.Website<>,
   valid?: false

now I need to work out how to pattern match on the map

thanks

had to add [ ] to pattern match

defp handle_error([{:blogs, {message, _}}]), do: message

now my flash says “blogs exist”

thanks @andrewb

Good news.