-
Type: Improvement
-
Resolution: Fixed
-
Priority: Major - P3
-
Affects Version/s: None
-
Component/s: None
-
None
It is possible, in a Mongoid application, to declare a type on a field which already contains data in the database of other, incompatible types. When retrieving such data, Mongoid is presently inconsistent with what happens:
- Some types raise an exception.
- Some types replace the database value with nil.
- Some types replace the database value with a "default" value for the type.
- Some types end up placing a value of the wrong type in the field (thus essentially overriding the user's field type specification).
Research by dmitry.rybakov:
irb(main):015:0> Date.demongoize('i am so bad') date.rb:48:in `demongoize': undefined method `year' for "i am so bad":String (NoMethodError) irb(main):018:0> Time.demongoize('so am i') time.rb:57:in `demongoize': undefined method `getlocal' for "so am i":String (NoMethodError) irb(main):020:0> DateTime.demongoize('i am also bad') time.rb:57:in `demongoize': undefined method `getlocal' for "i am also bad":String (NoMethodError) irb(main):021:0> Float.demongoize('i am sooooooo bad') => 0.0 irb(main):022:0> Integer.demongoize('could not be worse') => 0 irb(main):023:0> Range.demongoize('and yet it can') => nil.. irb(main):024:0> Set.demongoize('i have no idea what i am doing') ruby/3.1.0/set.rb:280:in `do_with_enum': value must be enumerable (ArgumentError) irb(main):026:0> Regexp.demongoize(42).class.name => "Integer" irb(main):028:0> Hash.demongoize('i give up') => "i give up"
This manifests as:
class Foo include Mongoid::Document field :a end Foo.delete_all Foo.create!(a: 'zz') class Foo field :a, type: BigDecimal end p Foo.first, Foo.first.a produces: NoMethodError: undefined method `getlocal' for "zz":String Test with the code as proposed with BigDecimal field: class Foo include Mongoid::Document field :a end Foo.delete_all Foo.create!(a: 'zz') class Foo field :a, type: Time end p Foo.first, Foo.first.a produces: #<Foo _id: 61d76a95a15d5d4e9c038186, a: "zz"> nil
Note that the first of the four options causes difficulties when working with data that is stored in the database, the second two options can be considered to lose data, the last option can cause weird application errors down the line.
Mongoid should:
Behave consistently with all types that it supports
Document its behavior
Possible solutions could involve a global or a per-field option as to how to handle values in the database that cannot be cast to the defined field type.
The action items are as follows:
create the ``validate_db_attribute_types`` flag
document feature flag
standardize demongoization functionality (always raise, rescue on flag)
create InvalidDBValue error
write release note for this change
add documentation to Uncastable values section
add note to custom types protocol
- Revised design *
- Deongoization of uncastable values will always return nil
- Original value will be accessible in attributes_before_type_cast (will be done in
MONGOID-5404)
- duplicates
-
MONGOID-5385 Standardize demongoization of uncastable values
- Closed
- has to be done before
-
MONGOID-5425 Verify string mongoization into Date, Time, DateTime with time zones
- Closed
- is duplicated by
-
MONGOID-5385 Standardize demongoization of uncastable values
- Closed
-
MONGOID-5286 Float/Integer demongoization of non-empty string returns zero, should be nil
- Closed
- is related to
-
MONGOID-5222 Always mongoize uncastable values to nil
- Closed
- related to
-
MONGOID-5386 Pass through uncastable values in evolve
- Closed