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

inclusion: the outside value may be outside the allowable max value of the column #634

Closed
dammer opened this issue Dec 29, 2014 · 14 comments
Milestone

Comments

@dammer
Copy link

dammer commented Dec 29, 2014

I have spec which fail after upgrade to rails 4.2 from 4.1

# some model validation spec 
is_expected.to validate_inclusion_of(:market_id).in_array(Markets.codes + Markets.entries)

also

irb(main):012:0> Markets.codes
=> [1, 2, 3]

irb(main):014:0> Markets.entries
=> [Markets::Th, Markets::Id, Markets::Ph]

irb(main):018:0> Markets.entries.map(&:to_i)
=> [1, 2, 3]
#scheme definion
t.integer  "market_id",                   limit: 2,                   null: false
#model
validates :market_id, inclusion: { in: (Markets.codes + Markets.entries) }, on: :create
  # backtrace
  1) market_id
     Failure/Error: is_expected.to validate_inclusion_of(:market_id).in_array(Markets.codes + Markets.entries)
     RangeError:
       123456789 is out of range for ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Integer with limit 2
     # ./.bundle/ruby/2.1.0/gems/activerecord-4.2.0/lib/active_record/type/integer.rb:41:in `ensure_in_range'
     # ./.bundle/ruby/2.1.0/gems/activerecord-4.2.0/lib/active_record/type/integer.rb:34:in `cast_value'
     # ./.bundle/ruby/2.1.0/gems/activerecord-4.2.0/lib/active_record/type/value.rb:89:in `type_cast'
     # ./.bundle/ruby/2.1.0/gems/activerecord-4.2.0/lib/active_record/type/numeric.rb:15:in `type_cast'
     # ./.bundle/ruby/2.1.0/gems/activerecord-4.2.0/lib/active_record/type/value.rb:34:in `type_cast_from_user'
     # ./.bundle/ruby/2.1.0/gems/activerecord-4.2.0/lib/active_record/attribute.rb:100:in `type_cast'
     # ./.bundle/ruby/2.1.0/gems/activerecord-4.2.0/lib/active_record/attribute.rb:42:in `original_value'
     # ./.bundle/ruby/2.1.0/gems/activerecord-4.2.0/lib/active_record/attribute.rb:37:in `value'
     # ./.bundle/ruby/2.1.0/gems/activerecord-4.2.0/lib/active_record/attribute.rb:46:in `value_for_database'
     # ./.bundle/ruby/2.1.0/gems/activerecord-4.2.0/lib/active_record/attribute_methods/dirty.rb:164:in `store_original_raw_attribute'
     # ./.bundle/ruby/2.1.0/gems/activerecord-4.2.0/lib/active_record/attribute_methods/dirty.rb:93:in `write_attribute'
     # ./.bundle/ruby/2.1.0/gems/activerecord-4.2.0/lib/active_record/attribute_methods.rb:50:in `__temp__d61627b65647f59646'
     # ./.bundle/ruby/2.1.0/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/allow_value_matcher.rb:247:in `set_value'
     # ./.bundle/ruby/2.1.0/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/allow_value_matcher.rb:221:in `block in matches?'
     # ./.bundle/ruby/2.1.0/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/allow_value_matcher.rb:219:in `each'
     # ./.bundle/ruby/2.1.0/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/allow_value_matcher.rb:219:in `none?'
     # ./.bundle/ruby/2.1.0/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/allow_value_matcher.rb:219:in `matches?'
     # ./.bundle/ruby/2.1.0/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/validation_matcher.rb:43:in `allows_value_of'
     # ./.bundle/ruby/2.1.0/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb:412:in `disallows_value_outside_of_array?'
     # ./.bundle/ruby/2.1.0/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb:350:in `matches_for_array?'
     # ./.bundle/ruby/2.1.0/gems/shoulda-matchers-2.7.0/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb:328:in `matches?'
     # ./spec/models/user/market_spec.rb:5:in `block (2 levels) in <top (required)>'
@mcmire
Copy link
Collaborator

mcmire commented Dec 30, 2014

@dammer I don't remember this issue coming up but is this true even for 2.8.0.rc1?

@dammer
Copy link
Author

dammer commented Jan 3, 2015

@mcmire yes, this true for 2.8.0.rc1

     Failure/Error: is_expected.to validate_inclusion_of(:market_id).in_array(Markets.codes + Markets.entries)
     RangeError:
       123456789 is out of range for ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Integer with limit 2
     # ./.bundle/ruby/2.1.0/gems/activerecord-4.2.0/lib/active_record/type/integer.rb:41:in `ensure_in_range'
     # ./.bundle/ruby/2.1.0/gems/activerecord-4.2.0/lib/active_record/type/integer.rb:34:in `cast_value'
     # ./.bundle/ruby/2.1.0/gems/activerecord-4.2.0/lib/active_record/type/value.rb:89:in `type_cast'
     # ./.bundle/ruby/2.1.0/gems/activerecord-4.2.0/lib/active_record/type/numeric.rb:15:in `type_cast'
     # ./.bundle/ruby/2.1.0/gems/activerecord-4.2.0/lib/active_record/type/value.rb:34:in `type_cast_from_user'
     # ./.bundle/ruby/2.1.0/gems/activerecord-4.2.0/lib/active_record/attribute.rb:100:in `type_cast'
     # ./.bundle/ruby/2.1.0/gems/activerecord-4.2.0/lib/active_record/attribute.rb:42:in `original_value'
     # ./.bundle/ruby/2.1.0/gems/activerecord-4.2.0/lib/active_record/attribute.rb:37:in `value'
     # ./.bundle/ruby/2.1.0/gems/activerecord-4.2.0/lib/active_record/attribute.rb:46:in `value_for_database'
     # ./.bundle/ruby/2.1.0/gems/activerecord-4.2.0/lib/active_record/attribute_methods/dirty.rb:164:in `store_original_raw_attribute'
     # ./.bundle/ruby/2.1.0/gems/activerecord-4.2.0/lib/active_record/attribute_methods/dirty.rb:93:in `write_attribute'
     # ./.bundle/ruby/2.1.0/gems/activerecord-4.2.0/lib/active_record/attribute_methods.rb:50:in `__temp__d61627b65647f59646'
     # ./.bundle/ruby/2.1.0/gems/shoulda-matchers-2.8.0.rc1/lib/shoulda/matchers/active_model/allow_value_matcher.rb:247:in `set_value'
     # ./.bundle/ruby/2.1.0/gems/shoulda-matchers-2.8.0.rc1/lib/shoulda/matchers/active_model/allow_value_matcher.rb:221:in `block in matches?'
     # ./.bundle/ruby/2.1.0/gems/shoulda-matchers-2.8.0.rc1/lib/shoulda/matchers/active_model/allow_value_matcher.rb:219:in `each'
     # ./.bundle/ruby/2.1.0/gems/shoulda-matchers-2.8.0.rc1/lib/shoulda/matchers/active_model/allow_value_matcher.rb:219:in `none?'
     # ./.bundle/ruby/2.1.0/gems/shoulda-matchers-2.8.0.rc1/lib/shoulda/matchers/active_model/allow_value_matcher.rb:219:in `matches?'
     # ./.bundle/ruby/2.1.0/gems/shoulda-matchers-2.8.0.rc1/lib/shoulda/matchers/active_model/validation_matcher.rb:43:in `allows_value_of'
     # ./.bundle/ruby/2.1.0/gems/shoulda-matchers-2.8.0.rc1/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb:413:in `block in disallows_value_outside_of_array?'
     # ./.bundle/ruby/2.1.0/gems/shoulda-matchers-2.8.0.rc1/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb:412:in `each'
     # ./.bundle/ruby/2.1.0/gems/shoulda-matchers-2.8.0.rc1/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb:412:in `any?'
     # ./.bundle/ruby/2.1.0/gems/shoulda-matchers-2.8.0.rc1/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb:412:in `disallows_value_outside_of_array?'
     # ./.bundle/ruby/2.1.0/gems/shoulda-matchers-2.8.0.rc1/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb:350:in `matches_for_array?'
     # ./.bundle/ruby/2.1.0/gems/shoulda-matchers-2.8.0.rc1/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb:328:in `matches?'

@dolzenko
Copy link

dolzenko commented Jan 6, 2015

Same issue here, I wonder if [0] should respect the column limits, or should just calculate outside value instead of using hardcoded one (which overflows the column)

[0]

@nathany
Copy link

nathany commented Jan 6, 2015

Seeing essentially the same issue when upgrading to Rails 4.2, but with:

is_less_than_or_equal_to(2_147_483_647)
2147483648 is out of range for ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Integer with limit 4

I tried upgrading to 2.8.0.rc1 but still had the issue.

@mcmire mcmire added this to the 2.8.0 milestone Jan 9, 2015
@mcmire
Copy link
Collaborator

mcmire commented Jan 9, 2015

@nathany But 2147483648 is out of range for an integer column. I'm curious how this was working before...

Did something change in Rails 4.2 with regard to integer columns?

@mcmire
Copy link
Collaborator

mcmire commented Jan 9, 2015

Oh this is probably related to stuff that @sgrif did with typecasting and so forth. Looks like it will now explicitly raise an error, I think that wasn't there before.

@mcmire
Copy link
Collaborator

mcmire commented Jan 9, 2015

So looks like we have two issues here:

  • For validate_inclusion_of, the outside value chosen may exceed the allowable max value of the column
  • For validate_numericality_of if you use one less than the allowable max value of the column then you'll get an exception and not a failure. Related, if you use allow_value with a value that's outside the allowable max value of the column you'll get an exception and not a failure.

I'll rename this issue for the first case and make a new issue for the second one.

@mcmire mcmire changed the title RangeError in Rails 4.2 validate_inclusion_of inclusion: the outside value may be outside the allowable max value of the column Jan 9, 2015
@sgrif
Copy link

sgrif commented Jan 9, 2015

Yeah, the range stuff is new in 4.2. The reasoning is a long story, which I can give you the details of if you want, but the TL;DR is that if we don't do this, some databases will raise an exception some of the time, and it's better for us to just always give an exception (which isn't a DB error, so we can actually handle it) in a known place so it can be caught and handled if needed (which we do in methods like find and find_by)

@sgrif
Copy link

sgrif commented Jan 9, 2015

@nathany If you're testing is_less_than_or_equal_to(2_147_483_647), you can just remove the validation. It is impossible to persist values greater than 2,147,483,647 in Rails 4.2+ on 32-bit signed integer columns.

@sgrif
Copy link

sgrif commented Jan 9, 2015

For the issue with validate_inclusion_of, it should be safe to just rescue RangeError in allow_value, and treat the value as dis-allowed. That should fix all of the issues mentioned in this thread. Unless the user has a custom writer which could potentially raise a RangeError, this is the only place that a RangeError should come from.

@nathany
Copy link

nathany commented Jan 9, 2015

@sgrif Thanks. That's what I ended up doing. Though I still have the validation itself in place. I haven't yet looked into how Rails 4.2 presents the error to a user when the validation isn't there.

@mcmire
Copy link
Collaborator

mcmire commented Jan 23, 2015

Fixed by #642.

@mcmire mcmire closed this as completed Jan 23, 2015
jsonn pushed a commit to jsonn/pkgsrc that referenced this issue Jun 12, 2015
pkgsrc change: allow build on Ruby 2.2.

# 2.8.0

### Deprecations

* `ensure_length_of` has been renamed to `validate_length_of`.
  `ensure_length_of` is deprecated and will be removed in 3.0.0.

* `set_the_flash` has been renamed to `set_flash`. `set_the_flash` is
  deprecated and will be removed in 3.0.0.

* `set_session(:foo)` is deprecated in favor of `set_session[:foo]`.
  `set_session(:foo)` will be invalid syntax in 3.0.0.

* Using `should set_session[:key].to(nil)` to assert that that a value has not
  been set is deprecated. Please use `should_not set_session[:key]` instead.
  In 3.0.0, `should set_session[:key].to(nil)` will only pass if the value is
  truly nil.

### Bug fixes

* Fix `delegate_method` so that it works again with shoulda-context. ([#591])

* Fix `validate_uniqueness_of` when used with `scoped_to` so that when one of
  the scope attributes is a polymorphic `*_type` attribute and the model has
  another validation on the same attribute, the matcher does not fail with an
  error. ([#592])

* Fix `has_many` used with `through` so that when the association does not
  exist, and the matcher fails, it does not raise an error when producing the
  failure message. ([#588])

* Fix `have_and_belong_to_many` used with `join_table` so that it does not fail
  when `foreign_key` and/or `association_foreign_key` was specified on the
  association as a symbol instead of a string. ([#584])

* Fix `allow_value` when an i18n translation key is passed to `with_message` and
  the `:against` option is used to specify an alternate attribute. A bug here
  also happened to affect `validate_confirmation_of` when an i18n translation
  key is passed to `with_message`. ([#593])

* Fix `class_name` qualifier for association matchers so that if the model being
  referenced is namespaced, the matcher will correctly resolve the class before
  checking it against the association's `class_name`. ([#537])

* Fix `validate_inclusion_of` used with `with_message` so that it fails if given
  a message that does not match the message on the validation. ([#598])

* Fix `route` matcher so that when controller and action are specified in hash
  notation (e.g. `posts#show`), route parameters such as `id` do not need to be
  specified as a string but may be specified as a number as well. ([#602])

* Fix `allow_value`, `validate_numericality_of` and `validate_inclusion_of` so
  that they handle RangeErrors emitted from ActiveRecord 4.2. These exceptions
  arise whenever we attempt to set an attribute using a value that lies outside
  the range of the column (assuming the column is an integer). RangeError is now
  treated specially, failing the test instead of bubbling up as an error.
  ([#634], [#637], [#642])

### Features

* Add ability to test `:primary_key` option on associations. ([#597])

* Add `allow_blank` qualifier to `validate_uniqueness_of` to complement
  the `allow_blank` option. ([#543])

* Change `set_session` so that #[] and #to qualifiers are optional, similar to
  `set_flash`. That is, you can now say `should set_session` to assert that any
  flash value has been set, or `should set_session.to('value')` to assert that
  any value in the session is 'value'.

* Change `set_session` so that its #to qualifier supports regexps, similar to
  `set_flash`.

* Add `with_prefix` qualifier to `delegate_method` to correspond to the `prefix`
  option for Rails's `delegate` macro. ([#622])

* Add support for Rails 4.2, especially fixing `serialize` matcher to remove
  warning about `serialized_attributes` being deprecated. ([#627])

* Update `dependent` qualifier on association matchers to support `:destroy`,
  `:delete`, `:nullify`, `:restrict`, `:restrict_with_exception`, and
  `:restrict_with_error`. You can also pass `true` or `false` to assert that
  the association has (or has not) been declared with *any* dependent option.
  ([#631])

### Improvements

* Tweak `allow_value` failure message so that it reads a bit nicer when listing
  existing errors.

[#591]: thoughtbot/shoulda-matchers#591
[#592]: thoughtbot/shoulda-matchers#592
[#588]: thoughtbot/shoulda-matchers#588
[#584]: thoughtbot/shoulda-matchers#584
[#593]: thoughtbot/shoulda-matchers#593
[#597]: thoughtbot/shoulda-matchers#597
[#537]: thoughtbot/shoulda-matchers#537
[#598]: thoughtbot/shoulda-matchers#598
[#602]: thoughtbot/shoulda-matchers#602
[#543]: thoughtbot/shoulda-matchers#543
[#622]: thoughtbot/shoulda-matchers#622
[#627]: thoughtbot/shoulda-matchers#627
[#631]: thoughtbot/shoulda-matchers#631
[#634]: thoughtbot/shoulda-matchers#634
[#637]: thoughtbot/shoulda-matchers#637
[#642]: thoughtbot/shoulda-matchers#642

# 2.7.0

### Deprecations

* `ensure_inclusion_of` has been renamed to `validate_inclusion_of`.
  `ensure_inclusion_of` is deprecated and will be removed in 3.0.0.

* `ensure_exclusion_of` has been renamed to `validate_exclusion_of`.
  `ensure_exclusion_of` is deprecated and will be removed in 3.0.0.

### Bug fixes

* Fix `delegate_method` so that it does not raise an error if the method that
  returns the delegate object is private.

* Warn when `ensure_inclusion_of` is chained with `.in_array([false, true])`
  as well as with `.in_array([true, false])`.

* Fix `set_session` so that the `to` qualifier if given nil checks that the
  session variable in question was set to nil (previously this actually did
  nothing).

* Fix `filter_param` so that it works when `config.filter_parameters` contains
  regexes.

* Fix `delegate_method` so that it can be required independent of Active
  Support.

* Fix `validate_uniqueness_of`. When used against an unpersisted record whose
  model contained a non-nullable column other than the one being validated, the
  matcher would break. Even if the test set that column to a value beforehand,
  the record had to be persisted in order for the matcher to work. Now this is
  no longer the case and the record can remain unpersisted.

* Fix `validate_absence_of`: it required that a string be passed as the
  attribute name rather than a symbol (which is the usual and documented usage).

### Improvements

* `have_and_belongs_to_many` now checks to make sure that the join table
  contains the correct columns for the left- and right-hand side of the
  association.

* Reword failure message for `delegate_method` so that it's a little more
  helpful.

### Features

* Add new matcher `define_enum_for` to test usage of the `enum` macro introduced
  in Rails 4.1.
@andreierdoss
Copy link

andreierdoss commented Dec 9, 2017

I am getting this error
123456789 is out of range for ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Integer with limit 2
when I try to use
it { is_expected.to validate_inclusion_of(:value).in_array([-1, 1]) }.
I assume that this issue is related. FYI I am using Rails 4.2 and Postgresql.

I'm not too clear on what I need to do to overcome it. I didn't see anything in the documentation to address it. Please advise.

@mcmire
Copy link
Collaborator

mcmire commented Dec 21, 2017

@andreierdoss Sorry for the delay on this. Which version of the gem are you using?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants