diff --git a/lib/active_record/virtual_attributes/virtual_fields.rb b/lib/active_record/virtual_attributes/virtual_fields.rb index 90fb361e..55203e45 100644 --- a/lib/active_record/virtual_attributes/virtual_fields.rb +++ b/lib/active_record/virtual_attributes/virtual_fields.rb @@ -33,18 +33,20 @@ def virtual_field?(name) end def replace_virtual_fields(associations) - return associations if associations.blank? + return nil if associations.blank? - case associations - when String, Symbol - virtual_field?(associations) ? replace_virtual_fields(virtual_includes(associations)) : associations.to_sym - when Array - associations.collect { |association| replace_virtual_fields(association) }.compact - when Hash - replace_virtual_field_hash(associations) - else - associations - end + ret = + case associations + when String, Symbol + virtual_field?(associations) ? replace_virtual_fields(virtual_includes(associations)) : associations.to_sym + when Array + associations.filter_map { |association| replace_virtual_fields(association) } + when Hash + replace_virtual_field_hash(associations) + else + associations + end + simplify_includes(ret) end def replace_virtual_field_hash(associations) @@ -98,6 +100,18 @@ def merge_includes(hash1, hash2) merge_includes(include_to_hash(v1), v2) end end + + # @param [Hash|Array|Symbol|nil] + def simplify_includes(ret) + case ret + when Hash + ret.size <= 1 && ret.values.first.blank? ? ret.keys.first : ret + when Array + ret.size <= 1 ? ret.first : ret + else + ret + end + end end end end @@ -267,7 +281,7 @@ def arel_column(field, &block) end def construct_join_dependency(associations, join_type) # :nodoc: - associations = klass.replace_virtual_fields(associations) + associations = klass.replace_virtual_fields(associations) || {} super end }) diff --git a/spec/virtual_attributes_spec.rb b/spec/virtual_attributes_spec.rb index 95a76b3b..b0b723b6 100644 --- a/spec/virtual_attributes_spec.rb +++ b/spec/virtual_attributes_spec.rb @@ -127,10 +127,10 @@ it ".replace_virtual_fields" do expect(TestClass.replace_virtual_fields(:vcol1)).to be_nil expect(TestClass.replace_virtual_fields(:ref1)).to eq(:ref1) - expect(TestClass.replace_virtual_fields([:vcol1])).to eq([]) - expect(TestClass.replace_virtual_fields([:vcol1, :ref1])).to eq([:ref1]) - expect(TestClass.replace_virtual_fields(:vcol1 => {})).to eq({}) - expect(TestClass.replace_virtual_fields(:vcol1 => {}, :ref1 => {})).to eq(:ref1 => {}) + expect(TestClass.replace_virtual_fields([:vcol1].freeze)).to be_nil + expect(TestClass.replace_virtual_fields([:vcol1, :ref1].freeze)).to eq(:ref1) + expect(TestClass.replace_virtual_fields({:vcol1 => {}}.freeze)).to be_nil + expect(TestClass.replace_virtual_fields({:vcol1 => {}, :ref1 => {}}.freeze)).to eq(:ref1) end end end @@ -158,15 +158,15 @@ end it ".replace_virtual_fields" do - expect(test_sub_class.replace_virtual_fields(:vcol1)).to be_nil - expect(test_sub_class.replace_virtual_fields(:vcolsub1)).to be_nil + expect(test_sub_class.replace_virtual_fields(:vcol1)).to be_nil + expect(test_sub_class.replace_virtual_fields(:vcolsub1)).to be_nil expect(test_sub_class.replace_virtual_fields(:ref1)).to eq(:ref1) - expect(test_sub_class.replace_virtual_fields([:vcol1])).to eq([]) - expect(test_sub_class.replace_virtual_fields([:vcolsub1])).to eq([]) - expect(test_sub_class.replace_virtual_fields([:vcolsub1, :vcol1, :ref1])).to eq([:ref1]) - expect(test_sub_class.replace_virtual_fields(:vcol1 => {})).to eq({}) - expect(test_sub_class.replace_virtual_fields(:vcolsub1 => {})).to eq({}) - expect(test_sub_class.replace_virtual_fields(:vcolsub1 => {}, :vcol1 => {}, :ref1 => {})).to eq(:ref1 => {}) + expect(test_sub_class.replace_virtual_fields([:vcol1].freeze)).to be_nil + expect(test_sub_class.replace_virtual_fields([:vcolsub1].freeze)).to be_nil + expect(test_sub_class.replace_virtual_fields([:vcolsub1, :vcol1, :ref1].freeze)).to eq(:ref1) + expect(test_sub_class.replace_virtual_fields({:vcol1 => {}}.freeze)).to be_nil + expect(test_sub_class.replace_virtual_fields({:vcolsub1 => {}}.freeze)).to be_nil + expect(test_sub_class.replace_virtual_fields({:vcolsub1 => {}, :vcol1 => {}, :ref1 => {}}.freeze)).to eq(:ref1) end end end @@ -341,10 +341,10 @@ def hosts it ".replace_virtual_fields" do expect(TestClass.replace_virtual_fields(:vref1)).to be_nil expect(TestClass.replace_virtual_fields(:ref1)).to eq(:ref1) - expect(TestClass.replace_virtual_fields([:vref1])).to eq([]) - expect(TestClass.replace_virtual_fields([:vref1, :ref1])).to eq([:ref1]) - expect(TestClass.replace_virtual_fields(:vref1 => {})).to eq({}) - expect(TestClass.replace_virtual_fields(:vref1 => {}, :ref1 => {})).to eq(:ref1 => {}) + expect(TestClass.replace_virtual_fields([:vref1].freeze)).to be_nil + expect(TestClass.replace_virtual_fields([:vref1, :ref1].freeze)).to eq(:ref1) + expect(TestClass.replace_virtual_fields({:vref1 => {}}.freeze)).to be_nil + expect(TestClass.replace_virtual_fields({:vref1 => {}, :ref1 => {}}.freeze)).to eq(:ref1) end end end @@ -377,12 +377,12 @@ def hosts expect(test_sub_class.replace_virtual_fields(:vref1)).to be_nil expect(test_sub_class.replace_virtual_fields(:vrefsub1)).to be_nil expect(test_sub_class.replace_virtual_fields(:ref1)).to eq(:ref1) - expect(test_sub_class.replace_virtual_fields([:vref1])).to eq([]) - expect(test_sub_class.replace_virtual_fields([:vrefsub1])).to eq([]) - expect(test_sub_class.replace_virtual_fields([:vrefsub1, :vref1, :ref1])).to eq([:ref1]) - expect(test_sub_class.replace_virtual_fields(:vref1 => {})).to eq({}) - expect(test_sub_class.replace_virtual_fields(:vrefsub1 => {})).to eq({}) - expect(test_sub_class.replace_virtual_fields(:vrefsub1 => {}, :vref1 => {}, :ref1 => {})).to eq(:ref1 => {}) + expect(test_sub_class.replace_virtual_fields([:vref1].freeze)).to be_nil + expect(test_sub_class.replace_virtual_fields([:vrefsub1].freeze)).to be_nil + expect(test_sub_class.replace_virtual_fields([:vrefsub1, :vref1, :ref1].freeze)).to eq(:ref1) + expect(test_sub_class.replace_virtual_fields({:vref1 => {}}.freeze)).to be_nil + expect(test_sub_class.replace_virtual_fields({:vrefsub1 => {}}.freeze)).to be_nil + expect(test_sub_class.replace_virtual_fields({:vrefsub1 => {}, :vref1 => {}, :ref1 => {}}.freeze)).to eq(:ref1) end end end diff --git a/spec/virtual_includes_spec.rb b/spec/virtual_includes_spec.rb index 73988137..a8b8afb0 100644 --- a/spec/virtual_includes_spec.rb +++ b/spec/virtual_includes_spec.rb @@ -524,22 +524,27 @@ expect(Author.replace_virtual_fields([:book_with_most_bookmarks, :books])).to eq([{:books => :bookmarks}, :books]) expect(Author.replace_virtual_fields(["book_with_most_bookmarks", "books"])).to eq([{:books => :bookmarks}, :books]) expect(Author.replace_virtual_fields([{:book_with_most_bookmarks => {}}, :books])).to eq([{:books => :bookmarks}, :books]) - expect(Author.replace_virtual_fields([{:book_with_most_bookmarks => {}}, {:books => {}}])).to eq([{:books => :bookmarks}, {:books => {}}]) + expect(Author.replace_virtual_fields([{:book_with_most_bookmarks => {}}, {:books => {}}])).to eq([{:books => :bookmarks}, :books]) end it "handles hash form of delegates" do - expect(Book.replace_virtual_fields([{:author_name => {}}, {:author_name2 => {}}])).to eq([{:author => {}}, {:author => {}}]) + expect(Book.replace_virtual_fields([{:author_name => {}}, {:author_name2 => {}}])).to eq([:author, :author]) end it "handles non-'includes' virtual_attributes" do expect(Author.replace_virtual_fields(:nick_or_name)).to eq(nil) - expect(Author.replace_virtual_fields([:nick_or_name])).to eq([]) - expect(Author.replace_virtual_fields(:nick_or_name => {})).to eq({}) + expect(Author.replace_virtual_fields([:nick_or_name])).to eq(nil) + expect(Author.replace_virtual_fields(:nick_or_name => {})).to eq(nil) end it "handles deep includes with va indirect uses(:uses => :books => :bookmarks)" do expect(Author.replace_virtual_fields(:famous_co_authors => {})).to eq({:books => {:bookmarks => {}, :co_authors => {}}}) end + + it "handles arrays" do + value = Author.includes(:named_books).includes_values + expect(Author.replace_virtual_fields(value)).to eq(:books) + end end def preloaded(records, associations, preload_scope = nil)