Understanding "attribute_will_change!" method

activerecord, hstore, postgresql, ruby, ruby-on-rails

Solution

This is part of activemodel's change tracking system, which active record uses to know what it needs to write to the db (if anything).

When you call save on a record, then activerecord creates an update query for all the attributes that it considers changed (and if there are no changed attributes then it does nothing at all).

The accessors that activerecord generates for you handle this for you automatically, but in some cases its useful to tell activerecord that an attribute is dirty and needs changing (for example if you update something in place, circumventing the usual change tracking mechanism).

This is exactly what happens here: when you set a key for the stored attribute - rails modifies the hash (as opposed to assigning a new hash), and so a call to `_will_change!` is needed to keep the change tracking informed that the underlying attribute will need writing to the db the next time save is called.

Problem

I want to overwrite the `store_accessor`'s getter. Which can be found here. Code here: ``` # File activerecord/lib/active_record/store.rb, line 74 def store_accessor(store_attribute, *keys) keys = keys.flatten _store_accessors_module.module_eval do keys.each do |key| define_method("#{key}=") do |value| write_store_attribute(store_attribute, key, value) end define_method(key) do read_store_attribute(store_attribute, key) end end end self.stored_attributes[store_attribute] ||= [] self.stored_attributes[store_attribute] |= keys end ``` I achieved the functionality I was after, however if I were to also overwrite the setter, there is a method that is not clear to me, which is within the `write_store_attribute(...)` method (found here). The code is here: ``` # File activerecord/lib/active_record/store.rb, line 108 def write_store_attribute(store_attribute, key, value) attribute = initialize_store_attribute(store_attribute) if value != attribute[key] send :"#{store_attribute}_will_change!" attribute[key] = value end end ``` The method I don't understand is `"#{whatever_store_att}_will_change!"`. If I were to overwrite the setter I would use `update_attributes` or `update_column`. Is this method making the assignment `attribute[key]=value` actually modify the field in the DB, making it equivalent to a `update_attributes`?

Original source