diff --git a/app/models/concerns/has_custom_fields.rb b/app/models/concerns/has_custom_fields.rb index 25a6422b0e..c6e929d8e0 100644 --- a/app/models/concerns/has_custom_fields.rb +++ b/app/models/concerns/has_custom_fields.rb @@ -161,7 +161,7 @@ module HasCustomFields array_fields = {} - _custom_fields.each do |f| + _custom_fields.reload.each do |f| if dup[f.name].is_a? Array # we need to collect Arrays fully before we can compare them if !array_fields.has_key?(f.name) @@ -171,7 +171,7 @@ module HasCustomFields end elsif dup[f.name].is_a? Hash if dup[f.name].to_json != f.value - f.destroy + f.destroy! else dup.delete(f.name) end @@ -180,7 +180,7 @@ module HasCustomFields self.class.append_custom_field(t, f.name, f.value) if dup[f.name] != t[f.name] - f.destroy + f.destroy! else dup.delete(f.name) end @@ -198,11 +198,12 @@ module HasCustomFields dup.each do |k, v| if v.is_a? Array - v.each { |subv| _custom_fields.create(name: k, value: subv) } - elsif v.is_a? Hash - _custom_fields.create(name: k, value: v.to_json) + v.each { |subv| _custom_fields.create!(name: k, value: subv) } else - _custom_fields.create(name: k, value: v) + _custom_fields.create!( + name: k, + value: v.is_a?(Hash) ? v.to_json : v + ) end end diff --git a/spec/components/concern/has_custom_fields_spec.rb b/spec/components/concern/has_custom_fields_spec.rb index fc1f1a43e8..f1bf5933cb 100644 --- a/spec/components/concern/has_custom_fields_spec.rb +++ b/spec/components/concern/has_custom_fields_spec.rb @@ -193,5 +193,27 @@ describe HasCustomFields do expect(fields[item1.id]['not_whitelisted']).to be_blank expect(fields[item2.id]['e']).to eq('hallo') end + + it "handles interleaving saving properly" do + field_type = 'deep-nest-test' + CustomFieldsTestItem.register_custom_field_type(field_type, :json) + test_item = CustomFieldsTestItem.create! + + test_item.custom_fields[field_type] ||= {} + test_item.custom_fields[field_type]['b'] ||= {} + test_item.custom_fields[field_type]['b']['c'] = 'd' + test_item.save_custom_fields(true) + + db_item = CustomFieldsTestItem.find(test_item.id) + db_item.custom_fields[field_type]['b']['e'] = 'f' + test_item.custom_fields[field_type]['b']['e'] = 'f' + expected = { field_type => { 'b' => { 'c' => 'd', 'e' => 'f' } } } + + db_item.save_custom_fields(true) + expect(db_item.reload.custom_fields).to eq(expected) + + test_item.save_custom_fields(true) + expect(test_item.reload.custom_fields).to eq(expected) + end end end