diff options
Diffstat (limited to 'activerecord/lib/active_record/attribute_methods/dirty.rb')
-rw-r--r-- | activerecord/lib/active_record/attribute_methods/dirty.rb | 92 |
1 files changed, 48 insertions, 44 deletions
diff --git a/activerecord/lib/active_record/attribute_methods/dirty.rb b/activerecord/lib/active_record/attribute_methods/dirty.rb index 6a5c057384..d5702accaf 100644 --- a/activerecord/lib/active_record/attribute_methods/dirty.rb +++ b/activerecord/lib/active_record/attribute_methods/dirty.rb @@ -34,55 +34,56 @@ module ActiveRecord # <tt>reload</tt> the record and clears changed attributes. def reload(*) super.tap do - reset_changes + clear_changes_information end end def initialize_dup(other) # :nodoc: super - init_changed_attributes + calculate_changes_from_defaults end - def changed? - super || changed_in_place.any? + def changes_applied + super + store_original_raw_attributes end - def changed - super | changed_in_place + def clear_changes_information + super + original_raw_attributes.clear end - def attribute_changed?(attr_name, options = {}) - result = super - # We can't change "from" something in place. Only setters can define - # "from" and "to" - result ||= changed_in_place?(attr_name) unless options.key?(:from) - result + def changed_attributes + # This should only be set by methods which will call changed_attributes + # multiple times when it is known that the computed value cannot change. + if defined?(@cached_changed_attributes) + @cached_changed_attributes + else + super.reverse_merge(attributes_changed_in_place).freeze + end end - def changes_applied - super - store_original_raw_attributes + def changes + cache_changed_attributes do + super + end end - def reset_changes - super - original_raw_attributes.clear + def attribute_changed_in_place?(attr_name) + old_value = original_raw_attribute(attr_name) + @attributes[attr_name].changed_in_place_from?(old_value) end private - def initialize_internals_callback - super - init_changed_attributes + def changes_include?(attr_name) + super || attribute_changed_in_place?(attr_name) end - def init_changed_attributes + def calculate_changes_from_defaults @changed_attributes = nil - # Intentionally avoid using #column_defaults since overridden defaults (as is done in - # optimistic locking) won't get written unless they get marked as changed - self.class.columns.each do |c| - attr, orig_value = c.name, c.default - changed_attributes[attr] = orig_value if _field_changed?(attr, orig_value) + self.class.column_defaults.each do |attr, orig_value| + set_attribute_was(attr, orig_value) if _field_changed?(attr, orig_value) end end @@ -108,9 +109,9 @@ module ActiveRecord def save_changed_attribute(attr, old_value) if attribute_changed?(attr) - changed_attributes.delete(attr) unless _field_changed?(attr, old_value) + clear_attribute_changes(attr) unless _field_changed?(attr, old_value) else - changed_attributes[attr] = old_value if _field_changed?(attr, old_value) + set_attribute_was(attr, old_value) if _field_changed?(attr, old_value) end end @@ -118,7 +119,7 @@ module ActiveRecord if attribute_changed?(attr) changed_attributes[attr] else - clone_attribute_value(:read_attribute, attr) + clone_attribute_value(:_read_attribute, attr) end end @@ -137,22 +138,20 @@ module ActiveRecord end def _field_changed?(attr, old_value) - new_value = read_attribute(attr) - raw_value = read_attribute_before_type_cast(attr) - column_for_attribute(attr).changed?(old_value, new_value, raw_value) + @attributes[attr].changed_from?(old_value) end - def changed_in_place - self.class.attribute_names.select do |attr_name| - changed_in_place?(attr_name) + def attributes_changed_in_place + changed_in_place.each_with_object({}) do |attr_name, h| + orig = @attributes[attr_name].original_value + h[attr_name] = orig end end - def changed_in_place?(attr_name) - type = type_for_attribute(attr_name) - old_value = original_raw_attribute(attr_name) - value = read_attribute(attr_name) - type.changed_in_place?(old_value, value) + def changed_in_place + self.class.attribute_names.select do |attr_name| + attribute_changed_in_place?(attr_name) + end end def original_raw_attribute(attr_name) @@ -166,9 +165,7 @@ module ActiveRecord end def store_original_raw_attribute(attr_name) - type = type_for_attribute(attr_name) - value = type.type_cast_for_database(read_attribute(attr_name)) - original_raw_attributes[attr_name] = value + original_raw_attributes[attr_name] = @attributes[attr_name].value_for_database end def store_original_raw_attributes @@ -176,6 +173,13 @@ module ActiveRecord store_original_raw_attribute(attr) end end + + def cache_changed_attributes + @cached_changed_attributes = changed_attributes + yield + ensure + remove_instance_variable(:@cached_changed_attributes) + end end end end |