Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Changeset 9139

Show
Ignore:
Timestamp:
03/29/08 22:19:26 (5 months ago)
Author:
bitsweat
Message:

Dirty typecasts attribute values before comparison, if possible. Closes #11464 [Russell Norris, mroch]

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/activerecord/lib/active_record/dirty.rb

    r9127 r9139  
    9292 
    9393          # Remember the original value if it's different. 
    94           changed_attributes[attr] = old unless old == value 
     94          typecasted = if column = column_for_attribute(attr) 
     95                         column.type_cast(value) 
     96                       else 
     97                         value 
     98                       end 
     99          changed_attributes[attr] = old unless old == typecasted 
    95100        end 
    96101 
  • trunk/activerecord/test/cases/dirty_test.rb

    r9127 r9139  
    11require 'cases/helper' 
     2require 'models/topic'    # For booleans 
     3require 'models/pirate'   # For timestamps 
    24 
    3 # Stub out an AR-alike. 
    4 class DirtyTestSubject 
    5   def self.table_name;  'people' end 
    6   def self.primary_key; 'id' end 
    7   def self.attribute_method_suffix(*suffixes) suffixes end 
     5class Pirate # Just reopening it, not defining it 
     6  attr_accessor :detected_changes_in_after_update # Boolean for if changes are detected 
     7  attr_accessor :changes_detected_in_after_update # Actual changes 
    88 
    9   def initialize(attrs = {}) @attributes = attrs end 
     9  after_update :check_changes 
    1010 
    11   def save 
    12     changed_attributes.clear 
     11private 
     12  # after_save/update in sweepers, observers, and the model itself 
     13  # can end up checking dirty status and acting on the results 
     14  def check_changes 
     15    if self.changed? 
     16      self.detected_changes_in_after_update = true 
     17      self.changes_detected_in_after_update = self.changes 
     18    end 
    1319  end 
    14  
    15   alias_method :save!, :save 
    16  
    17   def name; read_attribute('name') end 
    18   def name=(value); write_attribute('name', value) end 
    19   def name_was; attribute_was('name') end 
    20   def name_change; attribute_change('name') end 
    21   def name_changed?; attribute_changed?('name') end 
    22  
    23   private 
    24     def define_read_methods; nil end 
    25  
    26     def read_attribute(attr) 
    27       @attributes[attr] 
    28     end 
    29  
    30     def write_attribute(attr, value) 
    31       @attributes[attr] = value 
    32     end 
    3320end 
    34  
    35 # Include the module after the class is all set up. 
    36 DirtyTestSubject.module_eval { include ActiveRecord::Dirty } 
    37  
    3821 
    3922class DirtyTest < Test::Unit::TestCase 
    4023  def test_attribute_changes 
    4124    # New record - no changes. 
    42     person = DirtyTestSubject.new 
    43     assert !person.name_changed? 
    44     assert_nil person.name_change 
     25    pirate = Pirate.new 
     26    assert !pirate.catchphrase_changed? 
     27    assert_nil pirate.catchphrase_change 
    4528 
    46     # Change name. 
    47     person.name = 'a
    48     assert person.name_changed? 
    49     assert_nil person.name_was 
    50     assert_equal [nil, 'a'], person.name_change 
     29    # Change catchphrase. 
     30    pirate.catchphrase = 'arrr
     31    assert pirate.catchphrase_changed? 
     32    assert_nil pirate.catchphrase_was 
     33    assert_equal [nil, 'arrr'], pirate.catchphrase_change 
    5134 
    5235    # Saved - no changes. 
    53     person.save! 
    54     assert !person.name_changed? 
    55     assert_nil person.name_change 
     36    pirate.save! 
     37    assert !pirate.catchphrase_changed? 
     38    assert_nil pirate.catchphrase_change 
    5639 
    5740    # Same value - no changes. 
    58     person.name = 'a
    59     assert !person.name_changed? 
    60     assert_nil person.name_change 
     41    pirate.catchphrase = 'arrr
     42    assert !pirate.catchphrase_changed? 
     43    assert_nil pirate.catchphrase_change 
    6144  end 
    6245 
     46  # Rewritten from original tests to use AR 
    6347  def test_object_should_be_changed_if_any_attribute_is_changed 
    64     person = DirtyTestSubject.new 
    65     assert !person.changed? 
    66     assert_equal [], person.changed 
    67     assert_equal Hash.new, person.changes 
     48    pirate = Pirate.new 
     49    assert !pirate.changed? 
     50    assert_equal [], pirate.changed 
     51    assert_equal Hash.new, pirate.changes 
    6852 
    69     person.name = 'a
    70     assert person.changed? 
    71     assert_nil person.name_was 
    72     assert_equal %w(name), person.changed 
    73     assert_equal({'name' => [nil, 'a']}, person.changes) 
     53    pirate.catchphrase = 'arrr
     54    assert pirate.changed? 
     55    assert_nil pirate.catchphrase_was 
     56    assert_equal %w(catchphrase), pirate.changed 
     57    assert_equal({'catchphrase' => [nil, 'arrr']}, pirate.changes) 
    7458 
    75     person.save 
    76     assert !person.changed? 
    77     assert_equal [], person.changed 
    78     assert_equal({}, person.changes) 
     59    pirate.save 
     60    assert !pirate.changed? 
     61    assert_equal [], pirate.changed 
     62    assert_equal Hash.new, pirate.changes 
     63  end 
     64 
     65  def test_attribute_should_be_compared_with_type_cast 
     66    topic = Topic.new 
     67    assert topic.approved? 
     68    assert !topic.approved_changed? 
     69 
     70    # Coming from web form. 
     71    params = {:topic => {:approved => 1}} 
     72    # In the controller. 
     73    topic.attributes = params[:topic] 
     74    assert topic.approved? 
     75    assert !topic.approved_changed? 
    7976  end 
    8077end