I'm wondering if there is something at work here that I don't understand or if I've run into a bug in ActiveRecord (4.1.1).
I have a database full of records with only one attribute, a field a bit of JSON in it. I take one and try to update it like so.
test = Submission.find(1)
test.update_attribute('json_data',similar_but_different_json(test.json_data))
Let's assume the method similar_but_different_json
makes a small update to that JSON. In my case I'm fixing some data errors that were created by a broken form.
When doing this, I don't get any errors, I show a commit in the console but no data submitted and get a return of true
.
In order to actually update the record I have to do this.
test = Submission.find(1)
old_json_data = test.json_data
test.json_data = ""
test.json_data = similar_but_different_json(old_json_data)
test.save
What seems to be happening is that ActiveRecord doesn't identify that a change has been made that has to be saved. Could this be why setting the field to an empty string then back to JSON allows the record to save?
will_change!
You can also use:
test.json_data_will_change! # Goes before the save.
This will tell ActiveModel that the attribute, json_data
, has changed (i.e. it's dirty ← there's a joke there somewhere) and will update the value properly on save.
See Rails is not saving an attribute that is changed for some more details as well.
I don't understand why exactly the object is not marked dirty. A workaround is to use update_columns
:
test.update_columns(json_data: similar_but_different_json(test.json_data))
It will execute an UPDATE query directly in the DB, without any validation, dirty check, etc... The json_data
field must not be read-only though.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With