I am using ActiveModel::Dirty to track changes made in a form. Now everything is working as I expect. With stuff like phone numbers that get dashes in them when in the form I simply format them and then the phone number will not appear in the list of .changed
which is expected behavior.
However I run into an issue where I am using a jsonb field in my Profile model. So the issue is ActiveModel will list the JSONB field as being changed even though I format it specifically to match how it looked before. This is not expected behavior. What's stranger still is that another JSONB column I have does not experience this madness.
The JSONB field I'm having trouble with looks like this
store_accessor :user_details, :names, :other_field
store_accessor :bank_details, :bank_city, :bank_name
user_details
and bank_details
are jsonb columns.
Some things to note: names is an array, other_field is a string.
bank_city and bank_name are strings.
Can anyone shed some insight into why :user_details specifically is struggling with this issue and not the :bank_details JSON column?
I am suspecting it might be due to me using an array within the :user_details and I suspect that the comparison is being thrown off somewhere in the ActiveModel source code, but maybe I'm wrong?
Edit: I have discovered it is definitely because I am using an array for :names. I changed it to be a string and it stopped thinking that the JSON column had been changed. Going to dig into the ActiveModel source code to see if I can find a reason why.
Edit #2: For some reason I thought I solved the issue by doing nothing but I'm a dummy and realized that I had removed something in the form. So this issue still hasn't been solved for me. Any insight would be amazing. I can't figure out from looking into the ActiveModel::Dirty source code why this is happening. I'm not entirely sure where to look. Going to slap in byebugs to see if that helps.
Edit #3: Steps to repeat this issue
Create a rails Model with a JSONB column. Set store accessors you just need one to do this. Have it default using either a validator or formatter to be an empty array. Give your model the ActiveModel::Dirty include. Run the rails console. run the following commands. Imagine that user_details is the JSONB column and its store accessor is names.
a = Profile.user_details
a.user_details = { "names" => [{"first_name" => "", "last_name" => "" }] } # This is to replicate what it would look like in a form when a user is submitting a blank entry.
a.changed # This will show that user_details has changed which is correct
a.names = []
a.changed # This will still show that user_details has changed even though it has been set back to its initial state of an empty array. This would work if it was a string field instead of an array.