Shoulda-matchers: validates_uniqueness_of fails in Postgresql for type date column scope

Created on 4 Nov 2014  ·  8Comments  ·  Source: thoughtbot/shoulda-matchers

There is a related issue at https://github.com/thoughtbot/shoulda-matchers/issues/521

I am using ruby (2.0.0-p481), rails and activerecord (4.0.2), rspec-core (3.1.7), rspec-expectations (3.1.2), rspec-rails (3.1.0), postgres (9.3.5_1), and shoulda-matchers (2.7.0). I am trying to match the following model code:

validates_uniqueness_of :name, scope: :date_of_birth  # :name is type :string, date_of_birth is type :date

The shoulda-matcher it { should validate_uniqueness_of(:name).scoped_to(:date_of_birth) } does not find the type :date with which to match date_of_birth so it unsuccessfully tries to use the integer 1:

  1) Client should require case sensitive unique value for name scoped to date_of_birth
     Failure/Error: it { should validate_uniqueness_of(:name).scoped_to(:date_of_birth) }
     ActiveRecord::StatementInvalid:
       PG::UndefinedFunction: ERROR:  operator does not exist: date = integer
       LINE 1: ...people"."name" = 'a' AND "people"."date_of_birth" = 1) LIMIT...
                                                                    ^
       HINT:  No operator matches the given name and argument type(s). You might need to add explicit type casts.
       : SELECT  1 AS one FROM "clients"  WHERE ("clients"."name" = 'a' AND "clients"."date_of_birth" = 1) LIMIT 1
# /Users/cindyward/.rvm/gems/ruby-2.0.0-p481/gems/activerecord-4.0.2/lib/active_record/connection_adapters/postgresql_adapter.rb:774:in `async_exec'
... (lots more errors)
# /Users/cindyward/.rvm/gems/ruby-2.0.0-p481/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/validation_message_finder.rb:61:in `validate_instance'
     # /Users/cindyward/.rvm/gems/ruby-2.0.0-p481/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/validation_message_finder.rb:57:in `validated_instance'
     # /Users/cindyward/.rvm/gems/ruby-2.0.0-p481/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/validation_message_finder.rb:53:in `errors'
     # /Users/cindyward/.rvm/gems/ruby-2.0.0-p481/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/validation_message_finder.rb:23:in `has_messages?'
     # /Users/cindyward/.rvm/gems/ruby-2.0.0-p481/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/allow_value_matcher.rb:256:in `has_messages?'
     # /Users/cindyward/.rvm/gems/ruby-2.0.0-p481/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/allow_value_matcher.rb:252:in `errors_match?'
     # /Users/cindyward/.rvm/gems/ruby-2.0.0-p481/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/allow_value_matcher.rb:222:in `block in matches?'
     # /Users/cindyward/.rvm/gems/ruby-2.0.0-p481/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/allow_value_matcher.rb:219:in `each'
     # /Users/cindyward/.rvm/gems/ruby-2.0.0-p481/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/allow_value_matcher.rb:219:in `none?'
     # /Users/cindyward/.rvm/gems/ruby-2.0.0-p481/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/allow_value_matcher.rb:219:in `matches?'
     # /Users/cindyward/.rvm/gems/ruby-2.0.0-p481/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/validation_matcher.rb:43:in `allows_value_of'
     # /Users/cindyward/.rvm/gems/ruby-2.0.0-p481/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb:335:in `block in validate_after_scope_change?'
     # /Users/cindyward/.rvm/gems/ruby-2.0.0-p481/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb:313:in `each'
     # /Users/cindyward/.rvm/gems/ruby-2.0.0-p481/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb:313:in `all?'
     # /Users/cindyward/.rvm/gems/ruby-2.0.0-p481/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb:313:in `validate_after_scope_change?'
     # /Users/cindyward/.rvm/gems/ruby-2.0.0-p481/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb:221:in `matches?'
     # ./spec/models/people_spec.rb:12:in `block (2 levels) in <top (required)>'

I believe the shoulda-matchers code that needs to change reads as follows:

def correct_type_for_column(column)
  if [:string, :binary, :text].include? column.type
    '0'
  elsif column.type == :datetime  # Need to include types :date and :time here
    DateTime.now                         # Need to strftime DateTime.now depending on type
...

The check for type :datetype also needs to include checks for types :date and :time with the appropriate application of strftime used on DateTime.now.

🐘 Postgres Bug

Most helpful comment

@cindyward1 Ah... okay. We are changing how you set up the gem in 3.0. Add the following to the bottom of rails_helper.rb (or spec_helper.rb if you don't have that):

Shoulda::Matchers.configure do |config|
  config.integrate do |with|
    with.test_framework :rspec
    with.library :rails
  end
end

All 8 comments

Thanks for filing this. I can't say when I'll get to this exactly, but at least it's a known issue now.

Hi @cindyward1, I just pushed a fix for this to master -- if you can, do you mind running your tests against it and let me know if you're still seeing this bug?

Hi Elliot, sorry, my test still bombs with the same error message (date_of_birth is type Date and shoulda_matchers is still trying to validate against integer). I looked in my Gemfile.lock to make sure I was using shoulda_matchers 2.8.0
Failures:
  1) Client should require case sensitive unique value for name scoped to date_of_birth     Failure/Error: it { should validate_uniqueness_of(:name).scoped_to(:date_of_birth) }     ActiveRecord::StatementInvalid:       PG::UndefinedFunction: ERROR:  operator does not exist: date = integer       LINE 1: ...ients"."name" = 'a' AND "clients"."date_of_birth" = 1) LIMIT...
If I'm doing something wrong in my validation PLMK ... Cindy

 On Friday, February 13, 2015 4:12 PM, Elliot Winkler <[email protected]> wrote:

Hi @cindyward1, I just pushed a fix for this to master -- if you can, do you mind running your tests against it and let me know if you're still seeing this bug?—
Reply to this email directly or view it on GitHub.

@cindyward1 Okay. Can you try pointing your Gemfile to use master instead of 2.8.0? (The version will read 3.0.0.alpha)

I apologize for misunderstanding you before :(
I've got everything pointed at your repository's master branch and now ALL my tests are failing because of undefined methods. (Everything before worked except the scoping example.) Can you give me a quick hint as to what I'm doing wrong? (Maybe something pertaining to the RSpec::ExampleGroups module shown in the error messages below?) I am including require 'shoulda/matchers' in spec_helper.rb and my rspec-rails version only changed from 3.1.0 to 3.2.0.
Examples of the problems I'm having:
Failures:
  1) ClientAvailability      Failure/Error: it { should belong_to :client_schedule }     NoMethodError:       undefined method belong_to' for #<RSpec::ExampleGroups::ClientAvailability:0x007fd6d9951480>     # ./spec/models/client_availability_spec.rb:6:inblock (2 levels) in   3) ClientAvailability      Failure/Error: it { should validate_presence_of :client_id }     NoMethodError:       undefined method validate_presence_of' for #<RSpec::ExampleGroups::ClientAvailability:0x007fd6d9998b50>     # ./spec/models/client_availability_spec.rb:7:inblock (2 levels) in I imagine it's something simple I'm doing or not doing. Thanks in advance for your help ... Cindy

 On Monday, February 16, 2015 12:43 PM, Elliot Winkler <[email protected]> wrote:

@cindyward1 Okay. Can you try pointing your Gemfile to use master instead of 2.8.0? (The version will read 3.0.0.alpha)—
Reply to this email directly or view it on GitHub.

I should have mentioned: I'm using Ruby 2.0.0-p598 rather than a 2.1.x version. The reason is historical. I'm also using Rails 4.0.2, not a 4.1.x version or 4.2.0 .... Cindy

 On Monday, February 16, 2015 1:33 PM, Cindy Ward <[email protected]> wrote:

I apologize for misunderstanding you before :(
I've got everything pointed at your repository's master branch and now ALL my tests are failing because of undefined methods. (Everything before worked except the scoping example.) Can you give me a quick hint as to what I'm doing wrong? (Maybe something pertaining to the RSpec::ExampleGroups module shown in the error messages below?) I am including require 'shoulda/matchers' in spec_helper.rb and my rspec-rails version only changed from 3.1.0 to 3.2.0.
Examples of the problems I'm having:
Failures:
  1) ClientAvailability      Failure/Error: it { should belong_to :client_schedule }     NoMethodError:       undefined method belong_to' for #<RSpec::ExampleGroups::ClientAvailability:0x007fd6d9951480>     # ./spec/models/client_availability_spec.rb:6:inblock (2 levels) in   3) ClientAvailability      Failure/Error: it { should validate_presence_of :client_id }     NoMethodError:       undefined method validate_presence_of' for #<RSpec::ExampleGroups::ClientAvailability:0x007fd6d9998b50>     # ./spec/models/client_availability_spec.rb:7:inblock (2 levels) in I imagine it's something simple I'm doing or not doing. Thanks in advance for your help ... Cindy

 On Monday, February 16, 2015 12:43 PM, Elliot Winkler <[email protected]> wrote:

@cindyward1 Okay. Can you try pointing your Gemfile to use master instead of 2.8.0? (The version will read 3.0.0.alpha)—
Reply to this email directly or view it on GitHub.

@cindyward1 Ah... okay. We are changing how you set up the gem in 3.0. Add the following to the bottom of rails_helper.rb (or spec_helper.rb if you don't have that):

Shoulda::Matchers.configure do |config|
  config.integrate do |with|
    with.test_framework :rspec
    with.library :rails
  end
end

Thanks for the advance warning about the additional shoulda-matchers config. Now your change works great, thanks! I did have to change a couple of ensure_length_of validations to validate_length_of 
I guess I need to change all of my spec_helper.rb files to be rails_helper.rb files. I was taught to always use spec_helper.rb but I guess that's only for earlier versions of rails.
Many thanks for your help ... Cindy

 On Monday, February 16, 2015 3:55 PM, Elliot Winkler <[email protected]> wrote:

@cindyward1 Ah... okay. We are changing how you set up the gem in 3.0. You'll need to add the following to the bottom of rails_helper.rb (or spec_helper.rb if you don't have that):Shoulda::Matchers.configure do |config|
config.integrate do |with|
with.test_framework :rspec
with.library :rails
end
end

Reply to this email directly or view it on GitHub.

Was this page helpful?
0 / 5 - 0 ratings