Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails 3.2.13 vs Rails 4.0.1 - changed? method changed?

I have recently noticed that the method changed? on ActiveRecord objects has changed between Rails 3.2.13 and Rails 4.0.1. The problem is with fields connected to integer fields in database. Let's assume I have model Model with number integer field:

# Rails 3.2.13

m = Model.last
m.number                #=> 5
m.number = '5hello'
m.number                #=> 5
m.number_changed?       #=> true
m.changed?              #=> true
m.changes               #=> {:number => [5,5]}

# Rails 4.0.1

m = Model.last
m.number                #=> 5
m.number = '5hello'
m.number                #=> 5
m.number_changed?       #=> false
m.changed?              #=> false
m.changes               #=> {}

This causes a number of extremely annoying issues with form validations - if a user is trying to change the integer value to have invalid characters (but the type cast will result in the same value as initial one), rails will not invoke save method and none of the validation (including numericality: { only_integer: true }) will be run.

I have managed to get around this problem by overriding number_changed? method to super || number.to_s != number_before_type_cast, however this is extremely ugly.

The question is: why was this changed? Is it a bug or is intentional change? How can it be fixed without overriding all meta methods for integer columns?

like image 465
BroiSatse Avatar asked Apr 13 '14 13:04

BroiSatse


1 Answers

I'm not sure on how you're running your validations, but I have a model on my rails app which is called ExtraField and have the following validation:

class ExtraField < ActiveRecord::Base

  # stuff

  validates :display_order, numericality: { only_integer: true }

  # more stuff

end

I'm using rails 4.0.5 and I can do the following:

e = ExtraField.first
e.display_order           #=> 1
e.valid?                  #=> true
e.errors.messages         #=> {}
e.display_order = '1banana'
e.display_order           #=> 1
e.display_order_changed?  #=> false
e.changed?                #=> false
e.valid?                  #=> false
e.errors.messages         #=> {:display_order=>["is not a number"]}

So, although the record indeed isn't marked as changed ( what seems correct IMHO ), I can still run my validations and check that the model is not valid. Doesn't look like a bug to me, but just an intentional improvement.

If your form is only validating if the model is responding true to changed? maybe you should check your controller code. Or if you use a gem to help building the form it could be a bug in that gem I guess.

like image 125
oesgalha Avatar answered Oct 04 '22 17:10

oesgalha