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 1104 1104 developers = Developer.find(:all, :order => 'id') 1105 1105 assert_equal 10, developers.size 1106 1106 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 1107 1138 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 1108 1151 # FIXME: this test ought to run, but it needs to run sandboxed so that it 1109 1152 # doesn't b0rk the current test environment by undefing everything. 1110 1153 # -
lib/active_record/base.rb
old new 906 906 end 907 907 908 908 object.instance_variable_set("@attributes", record) 909 object.instance_eval("reset_changed_attributes") 909 910 object 910 911 end 911 912 … … 1189 1190 def initialize(attributes = nil) 1190 1191 @attributes = attributes_from_column_definition 1191 1192 @new_record = true 1193 reset_changed_attributes 1192 1194 ensure_proper_type 1193 1195 self.attributes = attributes unless attributes.nil? 1194 1196 yield self if block_given? … … 1229 1231 def save 1230 1232 raise ActiveRecord::ReadOnlyRecord if readonly? 1231 1233 create_or_update 1234 reset_changed_attributes 1232 1235 end 1233 1236 1234 1237 # Deletes the record in the database and freezes this instance to reflect that no changes should … … 1311 1314 def reload 1312 1315 clear_aggregation_cache 1313 1316 clear_association_cache 1317 reset_changed_attributes 1314 1318 @attributes.update(self.class.find(self.id).instance_variable_get('@attributes')) 1315 1319 self 1316 1320 end … … 1365 1369 def has_attribute?(attr_name) 1366 1370 @attributes.has_key?(attr_name.to_s) 1367 1371 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 1368 1382 1369 1383 # Returns an array of names for the attributes available on this object sorted alphabetically. 1370 1384 def attribute_names … … 1438 1452 1439 1453 # Updates the associated record with values matching those of the instance attributes. 1440 1454 def update 1455 return true if changed_attributes.empty? 1441 1456 connection.update( 1442 1457 "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))} " + 1444 1459 "WHERE #{self.class.primary_key} = #{quote(id)}", 1445 1460 "#{self.class.name} Update" 1446 1461 ) … … 1589 1604 else 1590 1605 @attributes[attr_name] = value 1591 1606 end 1607 @attributes_changed[attr_name] = true 1592 1608 end 1593 1609 1594 1610 def convert_number_column_value(value) … … 1637 1653 default << 'id' unless self.class.primary_key.eql? 'id' 1638 1654 default 1639 1655 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 1640 1661 1641 1662 # 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) 1644 1666 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 1647 1671 end 1648 1672 quoted 1649 1673 end