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
‹"[email protected]"›, and saving it as the existing record,
then making a new User and setting its :email to a different value,
‹"[email protected]"›, 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
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?
Yes my User model has this
validates_uniqueness_of :email
And I'm using User model with Devise.
@mcmire
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 "[email protected]", the other with an email of "[email protected]". 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 "[email protected]". 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 }
Thanks for the information, and it's working now!. I used this.
it { should validate_uniqueness_of(:email).ignoring_case_sensitivity }
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.
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.
validates :user, :name, :citizenship_status, :gender, :city, :about, :education, :last_job, :tech_background, :employment_objective, presence: true
validates :user, uniqueness: true
it { should validate_uniqueness_of(:user_id) }
it do
FactoryGirl.create(:applicant)
should validate_uniqueness_of(:user_id)
end
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)>'
I'm actually thinking this could be better somewhere else or in it's own issue. Sorry. Please advise when you get the chance.
@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?
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.
@batshoes Thank you for posting this. It helps other imperfect programmers, like me.
So - interestingly enough, I'm having this exact issue.
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
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
=> #Errors:0x007fe640fe7620
@base=
#
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"]}>
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.
@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.
I'm having the exact issue described above by @thewatts.
I'm running Rails 5, Ruby 2.3.1, PostgreSQL.
@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.
@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! 🎉
Most helpful comment
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 "[email protected]", the other with an email of "[email protected]". 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 "[email protected]". 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: