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

validates value uniqueness issue #553

Open
schinery opened this issue Mar 6, 2024 · 3 comments
Open

validates value uniqueness issue #553

schinery opened this issue Mar 6, 2024 · 3 comments

Comments

@schinery
Copy link

schinery commented Mar 6, 2024

Given the following:

class Client
  acts_as_paranoid without_default_scope: true

  validates :email, presence: true, uniqueness: { case_sensitive: false }
end

create_table "clients", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
  t.string "email", null: false
  t.datetime "deleted_at"
  t.index "lower((email)::text)", name: "index_clients_on_lower_email", unique: true
end

If I try and create a new client with the same email as a "deleted" client I get the following error:

ActiveRecord::RecordNotUnique (PG::UniqueViolation: ERROR:  duplicate key value violates unique constraint "index_clients_on_lower_email"
DETAIL:  Key (email)=([email protected]) already exists.
)

What I was expecting to happen was that it would trigger an "email is already taken" validation error because I have without_default_scope: true, so it should check against all clients, not just the non-deleted ones.

Is this what should be happening and something is wrong, or am I incorrect and need to do something else to validate against all clients.

I'm using:

Ruby 3.3.0
Rails 7.1.3.2
Paranoia 2.6.3

@schinery
Copy link
Author

schinery commented Mar 6, 2024

Also, I saw that there was #500, which looks like a similar thing but I didn't want to hijack that for my own purposes.

@mathieujobin
Copy link
Collaborator

kind of a boring workaround, but you could add :deleted_at column in the constraint.
what do you think ?

@myabc
Copy link

myabc commented May 20, 2024

If you're using PostgreSQL you should use partial indexes (see docs). Try replacing:

t.index "lower((email)::text)", name: "index_clients_on_lower_email", unique: true

with

t.index "lower((email)::text)", name: "index_clients_on_lower_email", unique: true, where: 'deleted_at IS NOT NULL'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants