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

Failing validate_uniqueness_of(:email) #935

Closed
rlopzc opened this issue Jun 14, 2016 · 15 comments
Closed

Failing validate_uniqueness_of(:email) #935

rlopzc opened this issue Jun 14, 2016 · 15 comments
Labels

Comments

@rlopzc
Copy link

rlopzc commented Jun 14, 2016

I'm validating the email is unique, however the test should pass, but the message is incoherent and the error too.

My test:
` subject { build(:user) }

it { should validate_uniqueness_of(:email) }`

`

  1. User should validate that :email is case-sensitively unique
    Failure/Error: it { should validate_uniqueness_of(:email) }
   User did not properly validate that :email is case-sensitively unique.
     After taking the given User, whose :email is
     ‹"josiah_koelpin@wiegand.biz"›, and saving it as the existing record,
     then making a new User and setting its :email to a different value,
     ‹"JOSIAH_KOELPIN@WIEGAND.BIZ"›, the matcher expected the new User to
     be valid, but it was invalid instead, producing these validation
     errors:

     * email: ["ya ha sido tomado"]
 # ./spec/models/user_spec.rb:48:in `block (2 levels) in <top (required)>'

`
The translation is in spanish, in english should be

has already been taken

@mcmire
Copy link
Collaborator

mcmire commented Jun 15, 2016

The matcher is describing the steps it took to run the test. What part of it is confusing?

Does your User model have a uniqueness validation on :email?

@rlopzc
Copy link
Author

rlopzc commented Jun 15, 2016

Yes my User model has this
validates_uniqueness_of :email

And I'm using User model with Devise.

@mcmire

@mcmire
Copy link
Collaborator

mcmire commented Jun 15, 2016

Okay. The reason why this is happening is that Devise overrides #email= to ensure that all emails are stored as lowercase in the database.

The matcher wants to create two records, one with an email address of "josiah_koelpin@wiegand.biz", the other with an email of "JOSIAH_KOELPIN@WIEGAND.BIZ". It expects this to work, because if it works, then it means your uniqueness validation is in place. However, because of Devise, the second user's email gets changed to "josiah_koelpin@wiegand.biz". So the matcher actually ends up trying to save two users with the same email address, and that doesn't work, because the uniqueness validation doesn't allow for that. So the matcher fails.

The message that you're getting should be a little more descriptive, and to be honest, I'm not sure why it's not -- I added something extra to detect this in the latest version. In any case, try using:

it { should validate_uniqueness_of(:email).ignoring_case_sensitivity }

@rlopzc
Copy link
Author

rlopzc commented Jun 15, 2016

Thanks for the information, and it's working now!. I used this.

it { should validate_uniqueness_of(:email).ignoring_case_sensitivity }

@mcmire
Copy link
Collaborator

mcmire commented Jun 16, 2016

Okay, cool. Glad I could help!

I'm going to keep this open to remind myself that we should make the user experience here better.

@mcmire mcmire added the UX label Jun 16, 2016
@batshoes
Copy link

batshoes commented Jul 5, 2016

Hi,
I am getting a similar error, (devise setup, uniqueness invalidation) but with a user_id on my "Applicant" Model. I have tried a few variations, but still seem to get the same error. Can't seem to isolate the issue.

Applicants Model Validations

validates :user, :name, :citizenship_status, :gender, :city, :about, :education, :last_job, :tech_background, :employment_objective, presence: true
 validates :user, uniqueness: true

Test Variations

it { should validate_uniqueness_of(:user_id) } 

it do
  FactoryGirl.create(:applicant)
  should validate_uniqueness_of(:user_id)
end

Exact error

Applicant did not properly validate that :user_id is unique.
         Given an existing Applicant whose :user_id is ‹227›, after making a
         new Applicant and setting its :user_id to ‹227› as well, the matcher
         expected the new Applicant to be invalid, but it was valid instead.
     # ./spec/models/applicants_model_spec.rb:36:in `block (2 levels) in <top (required)>'

**Edit

I'm actually thinking this could be better somewhere else or in it's own issue. Sorry. Please advise when you get the chance.

@mcmire
Copy link
Collaborator

mcmire commented Jul 7, 2016

@batshoes This may not be it, but you have a validation on :user while your test is using :user_id. Try changing the validation to match?

@batshoes
Copy link

batshoes commented Jul 7, 2016

Yikes.
That's embarrassing. Thank you for proof reading my code. Next time I'll send it it directly to you, instead of posting it publicly on github for everyone to see.

@l3x
Copy link

l3x commented Jul 21, 2016

@batshoes Thank you for posting this. It helps other imperfect programmers, like me.

@thewatts
Copy link

thewatts commented Aug 6, 2016

So - interestingly enough, I'm having this exact issue.

Spec:
RSpec.describe Course, type: :model do
  describe "validations" do
    subject { build(:course) }
    it { should validate_presence_of :title }
    it { should validate_uniqueness_of :title }
  end
end
Model:
class Course < ApplicationRecord
  validates :title, presence: true, uniqueness: true
end

Failed Spec Error

Failure/Error: it { should validate_uniqueness_of :title }

       Course did not properly validate that :title is case-sensitively unique.
         After taking the given Course, setting its :title to ‹"an arbitrary
         value"›, and saving it as the existing record, then making a new
         Course and setting its :title to ‹"an arbitrary value"› as well, the
         matcher expected the new Course to be invalid, but it was valid
         instead.

What's interesting - is that if I jump into the console, create a record with a title, then instantiate a new record with the same title - it validates title uniqueness.

Console Output showing invalid record

[12] pry(main)> dup.valid?
Course Exists (0.3ms) SELECT 1 AS one FROM "courses" WHERE "courses"."title" = $1 LIMIT $2 [["title", "BOOMTOWN"], ["LIMIT", 1]]
=> false
[13] pry(main)> dup.errors
=> #<ActiveModel::Errors:0x007fe640fe7620
@base=
#<Course:0x007fe645da9cc8
id: nil,
title: "BOOMTOWN",
trait_id: 1,
cover_image_file_name: nil,
cover_image_content_type: nil,
cover_image_file_size: nil,
cover_image_updated_at: nil,
created_at: nil,
updated_at: nil>,
@details={:title=>[{:error=>:taken, :value=>"BOOMTOWN"}]},
@messages={:title=>["has already been taken"]}>

@mminsaus
Copy link

mminsaus commented Aug 6, 2016

Try changing

{ subject build(:course) }

To

{ subject create(:course) }

Validations work on creation, like you are doing in the console, but FactoryGirl.build (which is what I am assuming you are using) is making a new unsaved instance
Alternatively try doing

subject.save 

Before running the validations.

@thewatts
Copy link

thewatts commented Aug 6, 2016

@mminsaus definitely a good thought! It looks like the result is the same.

Based on the error message when changing to create vs build - It looks like shoulda/matchers is responding to the objects differently.

When the subject is already created - shoulda/matchers will just create a new object and validate, whereas if the subject is a new record, shoulda/matchers will first save it and then create a new object for validation.

You can see more details in the error message given if the object is created (below) vs when it's just built (in my previous post)

FactoryGirl.create(:course) failed validation checking

  Course did not properly validate that :title is case-sensitively unique.
         Given an existing Course whose :title is ‹"Regaining Your Daily Drive
         #2"›, after making a new Course and setting its :title to ‹"Regaining
         Your Daily Drive #2"› as well, the matcher expected the new Course to
         be invalid, but it was valid instead.

@philtr
Copy link

philtr commented Aug 8, 2016

I'm having the exact issue described above by @thewatts.

I'm running Rails 5, Ruby 2.3.1, PostgreSQL.

@mcmire
Copy link
Collaborator

mcmire commented Aug 8, 2016

@thewatts I'm not sure why you would be seeing that. However, that seems like a different issue than this issue. Can you copy that to a new one so I can mark it appropriately as a Rails 5 issue? Thank you.

@thewatts
Copy link

thewatts commented Aug 8, 2016

@mcmire the issue on our end (both @philtr and myself) was due to a third party gem, challah.

Challah has been fixed - so this is no longer an issue for us! 🎉

@rlopzc rlopzc closed this as completed Dec 18, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants