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

Ticket #3238: changed_attributes.patch

File changed_attributes.patch, 5.7 kB (added by lsegal@holycraplions.com, 3 years ago)
  • test/base_test.rb

    old new  
    11041104    developers = Developer.find(:all, :order => 'id') 
    11051105    assert_equal 10, developers.size 
    11061106  end 
     1107 
     1108  def test_attribute_changed 
     1109    # Test for mass attribute and creation 
     1110    topic = Topic.new(:title => "Test Topic", :content => "Is this thing on?",  
     1111                      :author_name => "Loren", :author_email_address => "lsegal@holycraplions.com") 
     1112    assert topic.attribute_changed?(:title) 
     1113    assert topic.attribute_changed?(:author_email_address) 
     1114    assert_equal 4, topic.changed_attributes.size 
     1115    topic.save 
     1116    assert !topic.attribute_changed?(:title) 
     1117    assert_equal 0, topic.changed_attributes.size 
     1118     
     1119    # Test for an update 
     1120    topic.title = "We changed the topic" 
     1121    assert topic.attribute_changed?(:title) 
     1122    assert_equal ["title"], topic.changed_attributes 
     1123    topic.save 
     1124    assert !topic.attribute_changed?(:title) 
     1125    assert_equal 0, topic.changed_attributes.size 
     1126     
     1127    # Test for an existing record update 
     1128    topic = Topic.find(:first) 
     1129    assert !topic.attribute_changed?(:content) 
     1130    assert_equal 0, topic.changed_attributes.size 
     1131    topic.content = "We changed the content this time." 
     1132    assert topic.attribute_changed?(:content) 
     1133    assert_equal ["content"], topic.changed_attributes 
     1134    topic.save 
     1135    assert !topic.attribute_changed?(:content) 
     1136    assert_equal 0, topic.changed_attributes.size 
     1137  end 
    11071138   
     1139  def test_reset_changed_attributes 
     1140    topic = Topic.find(:first) 
     1141    topic.author_name = "Johnny" 
     1142    assert topic.attribute_changed?(:author_name) 
     1143    assert_equal ["author_name"], topic.changed_attributes 
     1144     
     1145    # Reload and check if attributes reset 
     1146    topic.reload 
     1147    assert !topic.attribute_changed?(:author_name) 
     1148    assert_equal 0, topic.changed_attributes.size 
     1149  end 
     1150 
    11081151  # FIXME: this test ought to run, but it needs to run sandboxed so that it 
    11091152  # doesn't b0rk the current test environment by undefing everything. 
    11101153  # 
  • lib/active_record/base.rb

    old new  
    906906            end 
    907907 
    908908          object.instance_variable_set("@attributes", record) 
     909          object.instance_eval("reset_changed_attributes") 
    909910          object 
    910911        end 
    911912 
     
    11891190      def initialize(attributes = nil) 
    11901191        @attributes = attributes_from_column_definition 
    11911192        @new_record = true 
     1193        reset_changed_attributes 
    11921194        ensure_proper_type 
    11931195        self.attributes = attributes unless attributes.nil? 
    11941196        yield self if block_given? 
     
    12291231      def save 
    12301232        raise ActiveRecord::ReadOnlyRecord if readonly? 
    12311233        create_or_update 
     1234        reset_changed_attributes 
    12321235      end 
    12331236 
    12341237      # Deletes the record in the database and freezes this instance to reflect that no changes should 
     
    13111314      def reload 
    13121315        clear_aggregation_cache 
    13131316        clear_association_cache 
     1317        reset_changed_attributes 
    13141318        @attributes.update(self.class.find(self.id).instance_variable_get('@attributes')) 
    13151319        self 
    13161320      end 
     
    13651369      def has_attribute?(attr_name) 
    13661370        @attributes.has_key?(attr_name.to_s) 
    13671371      end 
     1372       
     1373      # Returns true if the given attribute has been modified 
     1374      def attribute_changed?(attr_name) 
     1375        @attributes_changed.has_key?(attr_name.to_s) 
     1376      end 
     1377       
     1378      # Returns an array of attributes modified since last database read or save 
     1379      def changed_attributes 
     1380        @attributes_changed.keys 
     1381      end 
    13681382 
    13691383      # Returns an array of names for the attributes available on this object sorted alphabetically. 
    13701384      def attribute_names 
     
    14381452 
    14391453      # Updates the associated record with values matching those of the instance attributes. 
    14401454      def update 
     1455        return true if changed_attributes.empty? 
    14411456        connection.update( 
    14421457          "UPDATE #{self.class.table_name} " + 
    1443           "SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false))} " + 
     1458          "SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false, true))} " + 
    14441459          "WHERE #{self.class.primary_key} = #{quote(id)}", 
    14451460          "#{self.class.name} Update" 
    14461461        ) 
     
    15891604        else 
    15901605          @attributes[attr_name] = value 
    15911606        end 
     1607        @attributes_changed[attr_name] = true 
    15921608      end 
    15931609 
    15941610      def convert_number_column_value(value) 
     
    16371653        default << 'id' unless self.class.primary_key.eql? 'id' 
    16381654        default 
    16391655      end 
     1656       
     1657      # Resets attributes that have been modified since last database access or save 
     1658      def reset_changed_attributes 
     1659        @attributes_changed = {} 
     1660      end 
    16401661 
    16411662      # Returns copy of the attributes hash where all the values have been safely quoted for use in 
    1642       # an SQL statement. 
    1643       def attributes_with_quotes(include_primary_key = true) 
     1663      # an SQL statement. Can return only attributes that have been modified for an update of only  
     1664      # those specific values. 
     1665      def attributes_with_quotes(include_primary_key = true, only_changed_attributes = false) 
    16441666        attributes.inject({}) do |quoted, (name, value)| 
    1645           if column = column_for_attribute(name) 
    1646             quoted[name] = quote(value, column) unless !include_primary_key && column.primary 
     1667          unless only_changed_attributes && !attribute_changed?(name) 
     1668            if column = column_for_attribute(name) 
     1669              quoted[name] = quote(value, column) unless !include_primary_key && column.primary 
     1670            end 
    16471671          end 
    16481672          quoted 
    16491673        end