Rails validates_uniqueness_of ignoring scope

445 views Asked by At

I’m very new to Rails and am having trouble with Rails/ActiveRecord seemingly ignoring scope on a validates_uniqueness_of declaration in a project I’ve inherited. I have the following model:

class User < ActiveRecord::Base
  …
  validates_uniqueness_of :email, scope: :brand_id, allow_nil: true
  …
  belongs_to :brand
  …
end

There is an existing user record with an email of [email protected] and a brand_id of 1.

When trying to update another user record with an id of 123, email of [email protected] and a brand_id of 2, I get a Validation failed: Email has already been taken error.

I see the following two queries run one after the other when this error occurs:

SELECT  1 AS one FROM "users" WHERE ("users"."email" = '[email protected]' AND "users"."id" != 123) LIMIT 1;
SELECT  1 AS one FROM "users" WHERE ("users"."email" = '[email protected]' AND "users"."id" != 123 AND "users"."brand_id" = 2) LIMIT 1;

It looks like the second query is doing the correct uniqueness check, but the first one is ignoring the scope.

Any tips on what to look at or how to debug further would be appreciated.

2

There are 2 answers

1
Vlad On

There's nothing wrong with your logic in the model. There's something else that's stopping the Record to save.

Can you put the whole model?

class Artwork < ApplicationRecord

  ...

  validates_uniqueness_of :artwork_file_name, scope: :game_id

  ...

end


2.3.1 :810 > Artwork.new(artwork_file_name: 'asd', game_id: 100).save
   (12.5ms)  BEGIN
  Artwork Exists (92.1ms)  SELECT  1 AS one FROM `artworks` WHERE `artworks`.`artwork_file_name` = BINARY 'asd' AND `artworks`.`game_id` = 100 LIMIT 1
  SQL (64.1ms)  INSERT INTO `artworks` (`game_id`, `artwork_file_name`, `created_at`, `updated_at`) VALUES (100, 'asd', '2017-02-17 10:25:25', '2017-02-17 10:25:25')
   (17.9ms)  COMMIT
 => true
2.3.1 :811 > Artwork.new(artwork_file_name: 'asd', game_id: 100).save
   (0.2ms)  BEGIN
  Artwork Exists (0.5ms)  SELECT  1 AS one FROM `artworks` WHERE `artworks`.`artwork_file_name` = BINARY 'asd' AND `artworks`.`game_id` = 100 LIMIT 1
   (6.1ms)  ROLLBACK
 => false
2.3.1 :812 > Artwork.new(artwork_file_name: 'asd', game_id: 101).save
   (0.2ms)  BEGIN
  Artwork Exists (45.4ms)  SELECT  1 AS one FROM `artworks` WHERE `artworks`.`artwork_file_name` = BINARY 'asd' AND `artworks`.`game_id` = 101 LIMIT 1
  SQL (6.7ms)  INSERT INTO `artworks` (`game_id`, `artwork_file_name`, `created_at`, `updated_at`) VALUES (101, 'asd', '2017-02-17 10:26:05', '2017-02-17 10:26:05')
   (6.3ms)  COMMIT
 => true
2.3.1 :813 >
0
Jaik Dean On

It turned out to be Devise's "validatable" behaviour, which added it's own unique validation of the email field.