From 1e70c3cbbd11943618cf8123ba998c3d2cf634fd Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Fri, 25 Apr 2014 19:15:23 +0200 Subject: [PATCH] Add Support for Arrays to CustomFields --- lib/concern/has_custom_fields.rb | 63 ++++++++++++++++--- .../concern/has_custom_fields_spec.rb | 43 +++++++++++++ 2 files changed, 97 insertions(+), 9 deletions(-) diff --git a/lib/concern/has_custom_fields.rb b/lib/concern/has_custom_fields.rb index aadd3b91f..b0a61bd74 100644 --- a/lib/concern/has_custom_fields.rb +++ b/lib/concern/has_custom_fields.rb @@ -8,35 +8,80 @@ module Concern end def custom_fields - @custom_fields ||= begin - @custom_fields_orig = Hash[*_custom_fields.pluck(:name,:value).flatten] - @custom_fields_orig.dup - end + @custom_fields ||= refresh_custom_fields_from_db.dup end def custom_fields=(data) custom_fields.replace(data) end + def custom_fields_clean? + # Check whether the cached version has been + # changed on this model + !@custom_fields || @custom_fields_orig == @custom_fields + end + protected + def refresh_custom_fields_from_db + target = Hash.new + _custom_fields.pluck(:name,:value).each do |key, value| + if target.has_key? key + if !target[key].is_a? Array + target[key] = [target[key]] + end + target[key] << value + else + target[key] = value + end + end + @custom_fields_orig = target + @custom_fields = @custom_fields_orig.dup + end + def save_custom_fields - if @custom_fields && @custom_fields_orig != @custom_fields + if !custom_fields_clean? dup = @custom_fields.dup + array_fields = {} + _custom_fields.each do |f| - if dup[f.name] != f.value - f.destroy + 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 + array_fields[f.name] = [f] + else + array_fields[f.name] << f + end else + if dup[f.name] != f.value + f.destroy + else + dup.delete(f.name) + end + end + end + + # let's iterate through our arrays and compare them + array_fields.each do |field_name, fields| + if fields.length == dup[field_name].length && + fields.map{|f| f.value} == dup[field_name] dup.delete(f.name) + else + fields.each{|f| f.destroy } end end dup.each do |k,v| - _custom_fields.create(name: k, value: v) + if v.is_a? Array + v.each {|subv| _custom_fields.create(name: k, value: subv)} + else + _custom_fields.create(name: k, value: v) + end end - @custom_fields_orig = dup + refresh_custom_fields_from_db end end end diff --git a/spec/components/concern/has_custom_fields_spec.rb b/spec/components/concern/has_custom_fields_spec.rb index c5c5f7a60..9f8ae26aa 100644 --- a/spec/components/concern/has_custom_fields_spec.rb +++ b/spec/components/concern/has_custom_fields_spec.rb @@ -35,6 +35,7 @@ describe Concern::HasCustomFields do test_item.custom_fields["bob"] = "marley" test_item.custom_fields["jack"] = "black" + test_item.save test_item = TestItem.find(test_item.id) @@ -51,6 +52,21 @@ describe Concern::HasCustomFields do test_item.custom_fields.should == {"jack" => "jill"} end + it "casts integers to string without error" do + test_item = TestItem.new + test_item.custom_fields["a"].should == nil + test_item.custom_fields["a"] = 0 + + test_item.custom_fields["a"].should == 0 + test_item.save + + # should be casted right after saving + test_item.custom_fields["a"].should == "0" + + test_item = TestItem.find(test_item.id) + test_item.custom_fields["a"].should == "0" + end + it "double save actually saves" do test_item = TestItem.new @@ -66,6 +82,33 @@ describe Concern::HasCustomFields do end + it "handles arrays properly" do + + test_item = TestItem.new + test_item.custom_fields = {"a" => ["b", "c", "d"]} + test_item.save + + db_item = TestItem.find(test_item.id) + db_item.custom_fields.should == {"a" => ["b", "c", "d"]} + + db_item.custom_fields["a"] = ["c", "d"] + db_item.save + db_item.custom_fields.should == {"a" => ["c", "d"]} + + end + + it "casts integers in arrays properly without error" do + + test_item = TestItem.new + test_item.custom_fields = {"a" => ["b", 10, "d"]} + test_item.save + test_item.custom_fields.should == {"a" => ["b", "10", "d"]} + + db_item = TestItem.find(test_item.id) + db_item.custom_fields.should == {"a" => ["b", "10", "d"]} + + end + it "simple modifications don't interfere" do test_item = TestItem.new