Here’s some behavior you might not expect when using Postgres’s hstore with ActiveRecord.
ActiveRecord::Base#update_attributes does what you’d think:
However, ActiveRecord::Base#save might not:
Huh? I left the SQL log line in the output here so we can see that our hstore field is indeed left out of the SQL INSERT statement entirely, which explains why the field is
nil once we re-fetch the object from the database.
But why is it doing this? It turns out that, in Rails 4.0 and 4.1, this operation doesn’t mark the field as “dirty” in ActiveRecord, so the change is not detected and included in the save operation.
We can mark it manually with ActiveModel::Dirty’s
The documentation states that
attr_name_will_change! should be called before changes to the attribute, as seen in the example above.
Doesn’t this seem like a pain? Well, as discussed in Rails issue #6127, it was expected behavior for Rails 4.0 and 4.1, but improvements to serialized attributes have been merged into Rails and will appear in Rails 4.2. Setting values and calling save will just work.
So, in the meantime, the workaround is manually marking properties as dirty with
attr_data_will_change! before making and saving changes to those fields.