diff --git a/lib/jbuilder.rb b/lib/jbuilder.rb index d84eab21..c41ebb14 100644 --- a/lib/jbuilder.rb +++ b/lib/jbuilder.rb @@ -213,10 +213,8 @@ def array!(collection = [], *attributes) # # json.(@person, :name, :age) def extract!(object, *attributes) - if ::Hash === object - _extract_hash_values(object, attributes) - else - _extract_method_values(object, attributes) + attributes.each do |key| + _set_value key, _extract_value(object, key) end end @@ -252,12 +250,8 @@ def target! private - def _extract_hash_values(object, attributes) - attributes.each{ |key| _set_value key, object.fetch(key) } - end - - def _extract_method_values(object, attributes) - attributes.each{ |key| _set_value key, object.public_send(key) } + def _extract_value(object, attribute) + object.respond_to?(:[]) ? object[attribute] : object.public_send(attribute) end def _merge_block(key) diff --git a/test/jbuilder_test.rb b/test/jbuilder_test.rb index ae15c042..9ec11764 100644 --- a/test/jbuilder_test.rb +++ b/test/jbuilder_test.rb @@ -35,6 +35,14 @@ def initialize(name, age) end end +class PersonWithHash + def initialize(name, age, object_id) + @collection = { name: name, age: age, object_id: object_id } + end + + delegate :[], :fetch, to: :@collection +end + class RelationMock include Enumerable @@ -121,6 +129,20 @@ class JbuilderTest < ActiveSupport::TestCase assert_equal 34, result['age'] end + test 'extracting from object with internal hash' do + person = PersonWithHash.new('David', 32, 1) + ruby_object_id = person.object_id + + result = jbuild do |json| + json.extract! person, :name, :age, :object_id + end + + assert_equal 'David', result['name'] + assert_equal 32, result['age'] + assert_equal 1, result['object_id'] + assert_not_equal ruby_object_id, result['object_id'] + end + test 'nesting single child with block' do result = jbuild do |json| json.author do