Saturday, February 25, 2017

Rails 3 to 4 migration uniqueness validation issues

Leave a Comment

Context

We are migrating from Rails 3.2.12 to 4.0.2 and Ruby 1.9.3 to 2.1.8.

We have a lot of test coverage to accomplish the migration in the form of RSpec.

Issue

One of the spec that checks that a uniqueness validation on a Card model is failing.

validates :mobile, uniqueness: {scope: :program_member_id, message: I18n.t('models.card.error.cardholder_already_has_mobile')}, if: :mobile 

Where a program_member may only have one mobile: true card.

The spec creates 2 cards for the member, turns one into a mobile card, then expects the validation's message when doing so with the second card.

let(:program) { FactoryGirl.create(:program) } let(:card) { FactoryGirl.create(:card, program: program) }  context 'when cardholder already has a mobile card' do   it 'fails validation' do     card2 = FactoryGirl.create(:card, program: program)     program_member_user = FactoryGirl.create(:program_member_user, card_number: card2.cardnumber)     program_member = program_member_user.program_members.first      program_member.cards << card2     card2.update_attributes(:mobile => true)      program_member.cards << card     card.update_attributes(:mobile => true)      expect(card.errors.messages).to include(:mobile=>[I18n.t('models.card.error.cardholder_already_has_mobile')])   end end 

Expectation:

expected {} to include {:mobile=>["Cardholder already has a mobile card"]} 

When I go to our master branch, this spec passes.

The only factor that has changed from this spec working to failing is the Rails 3 to 4 migration.

Tried running the spec code in console only to find the member has 2 mobile cards and doing card.valid? returns true for both instances.

Question

Has anything changed in Rails 4 in regards to uniqueness validation or validation life cycle?

1 Answers

Answers 1

Alright so I'm onto something.

I created a test project using the same Ruby and Rails version.

https://github.com/frank184/test_uniquness

In this project, I would have a User model that has an admin column as a boolean with a similar validation.

validates_uniqueness_of :admin, if: :admin? 

I used shoulda-matchers and rspec to describe the desired outcome.

require 'rails_helper'  RSpec.describe User, type: :model do   let(:user) { build :user }   subject { user }    describe 'validations' do     context 'when admin = true' do       before(:each) { user.admin = true }       it { is_expected.to validate_uniqueness_of(:admin)  }     end   end end 

The spec failed with the following output:

Failures:    1) User validations when admin = true should validate that :admin is case-sensitively unique      Failure/Error: it { is_expected.to validate_uniqueness_of(:admin)  }         User did not properly validate that :admin is case-sensitively unique.          After taking the given User, whose :admin is ‹true›, and saving it as          the existing record, then making a new User and setting its :admin to          ‹true› as well, the matcher expected the new User to be invalid, but          it was valid instead.      # ./spec/models/user_spec.rb:10:in `block (4 levels) in <top (required)>'  Finished in 0.11435 seconds (files took 0.79997 seconds to load) 1 example, 1 failure 

I decided that the code was good and bumped Rails to 4.1.0 exactly.

The spec passed!

bundle update rspec .  Finished in 0.09538 seconds (files took 1.28 seconds to load) 1 example, 0 failures 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment