Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ecto.Changeset.no_assoc_constraint/3 does not work #124

Open
snofang opened this issue Sep 6, 2023 · 6 comments
Open

Ecto.Changeset.no_assoc_constraint/3 does not work #124

snofang opened this issue Sep 6, 2023 · 6 comments
Labels
bug Something isn't working

Comments

@snofang
Copy link

snofang commented Sep 6, 2023

Test environment:

Erlang/OTP 25 [erts-13.1.2] 
Elixir 1.14.2 
ecto 3.10.3
ecto_sql 3.10.1
ecto_sqlite3 0.10.3

Description:
Suppose it, as a completely straightforward use case, as the documentation of no_assoc_constraint/3 expressed (and the same code is working fine on postgrex).

P.S. As I am reporting this, I see there are two other releases come out and sounds like non of them addressed this issue, so I didn't check them.

@warmwaffles
Copy link
Member

sounds like non of them addressed this issue, so I didn't check them.

That is correct, none of them address this. We'll need to add unit tests for this and figure out why it was missed. This was a feature added 8 years ago to ecto.

@warmwaffles
Copy link
Member

Looks like a test would have covered this but we ignore it because we can't get nicely formatted FK errors

# sqlite supports FKs, but does not return sufficient data
# for ecto to support matching on a given constraint violation name
# which is what most of the tests validate
:foreign_key_constraint,

@warmwaffles warmwaffles added the bug Something isn't working label Sep 6, 2023
@jakeprem
Copy link

It seems this also applies to Ecto.Changeset.foreign_key_constraint/3

@warmwaffles
Copy link
Member

Yea it's mainly having to figure out how to capture that error from SQLite.

@jakeprem
Copy link

As a quick workaround I added the following to my repo module:

def safe_insert(changeset, opts \\ []) do
    insert(changeset, opts)
  rescue
    e in Ecto.ConstraintError ->
      handle_foreign_key_constraints(changeset, e)
  end

defp handle_foreign_key_constraints(%Ecto.Changeset{} = changeset, e) do
    %{constraints: constraints} = changeset
    foreign_key_constraints = Enum.filter(constraints, &(&1.type == :foreign_key))

    if e.type == :foreign_key and foreign_key_constraints != [] do
      error_changeset =
        Enum.reduce(foreign_key_constraints, changeset, fn constraint, changeset ->
          Ecto.Changeset.add_error(
            changeset,
            constraint.field,
            "may not exist (SQLite raised a foreign key constraint error but does not specify which one)"
          )
        end)

      {:error, error_changeset}
    else
      raise e
    end
end

There's likely a better workaround but hopefully that's helpful for anyone else running into this.

@warmwaffles
Copy link
Member

I'm not going to close this issue. When I get some time I'll fiddle around with the error outputs and see if we can't get more details about the failure to pick out the failing constraint. There has to be a way to make SQLite explain which one blew up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants