diff --git a/lib/oat/adapter.rb b/lib/oat/adapter.rb index 90d7c6e..342eabb 100644 --- a/lib/oat/adapter.rb +++ b/lib/oat/adapter.rb @@ -28,7 +28,7 @@ def serializer_from_block_or_class(obj, serializer_class = nil, context_options serializer_class = Class.new(serializer.class) serializer_class.adapter self.class s = serializer_class.new(obj, serializer.context.merge(context_options), serializer.adapter_class, serializer.top) - serializer.top.instance_exec(obj, s, &block) + serializer.instance_exec(obj, s, &block) s.to_hash else serializer_class.new(obj, serializer.context.merge(context_options), serializer.adapter_class, serializer.top).to_hash diff --git a/lib/oat/adapters/hal.rb b/lib/oat/adapters/hal.rb index 81a95ed..9d5f845 100644 --- a/lib/oat/adapters/hal.rb +++ b/lib/oat/adapters/hal.rb @@ -23,6 +23,7 @@ def entities(name, collection, serializer_class = nil, context_options = {}, &bl serializer_from_block_or_class(obj, serializer_class, context_options, &block) end end + alias_method :collection, :entities end end diff --git a/lib/oat/adapters/json_api.rb b/lib/oat/adapters/json_api.rb index 9fc30e9..67835dc 100644 --- a/lib/oat/adapters/json_api.rb +++ b/lib/oat/adapters/json_api.rb @@ -17,7 +17,7 @@ def initialize(*args) end def type(*types) - @root_name = types.first.to_s + @root_name = types.first.to_s.pluralize.to_sym end def link(rel, opts = {}) @@ -55,12 +55,27 @@ def entities(name, collection, serializer_class = nil, context_options = {}, &bl end end + def collection(name, collection, serializer_class = nil, context_options = {}, &block) + @treat_as_resource_collection = true + data[:resource_collection] = [] unless data[:resource_collection].is_a?(Array) + + collection.each do |obj| + ent = serializer_from_block_or_class(obj, serializer_class, context_options, &block) + data[:resource_collection] << ent if ent + end + end + def to_hash raise "JSON API entities MUST define a type. Use type 'user' in your serializers" unless root_name if serializer.top != serializer return data else - h = {root_name.pluralize.to_sym => [data]} + h = {} + if @treat_as_resource_collection + h[root_name] = data[:resource_collection] + else + h[root_name] = [data] + end h[:linked] = @entities if @entities.keys.any? return h end diff --git a/lib/oat/adapters/siren.rb b/lib/oat/adapters/siren.rb index e64f0bc..79f0d21 100644 --- a/lib/oat/adapters/siren.rb +++ b/lib/oat/adapters/siren.rb @@ -36,6 +36,7 @@ def entities(name, collection, serializer_class = nil, context_options = {}, &bl entity name, obj, serializer_class, context_options, &block end end + alias_method :collection, :entities def action(name, &block) action = Action.new(name) diff --git a/spec/adapters/json_api_spec.rb b/spec/adapters/json_api_spec.rb index 038166a..7e996b9 100644 --- a/spec/adapters/json_api_spec.rb +++ b/spec/adapters/json_api_spec.rb @@ -97,5 +97,75 @@ hash.fetch(:linked).fetch(:managers).should be_empty end end + + context 'with an entity collection' do + let(:serializer_collection_class) do + USER_SERIALIZER = serializer_class unless defined?(USER_SERIALIZER) + Class.new(Oat::Serializer) do + schema do + type 'users' + collection :users, item, USER_SERIALIZER + end + end + end + + let(:collection_serializer){ + serializer_collection_class.new( + [user,friend], + {:name => "some_controller"}, + Oat::Adapters::JsonAPI + ) + } + let(:collection_hash) { collection_serializer.to_hash } + + context 'top level' do + subject(:users){ collection_hash.fetch(:users) } + its(:size) { should eq(2) } + + it 'contains the correct first user properties' do + expect(users[0]).to include( + :id => user.id, + :name => user.name, + :age => user.age, + :controller_name => 'some_controller', + :message_from_above => nil + ) + end + + it 'contains the correct second user properties' do + expect(users[1]).to include( + :id => friend.id, + :name => friend.name, + :age => friend.age, + :controller_name => 'some_controller', + :message_from_above => nil + ) + end + + it 'contains the correct user links' do + expect(users.first.fetch(:links)).to include( + :self => "http://foo.bar.com/#{user.id}", + # these links are added by embedding entities + :manager => manager.id, + :friends => [friend.id] + ) + end + + context 'sub entity' do + subject(:linked_managers){ collection_hash.fetch(:linked).fetch(:managers) } + its(:size) { should eq(1) } + + it "contains the correct properties and links" do + expect(linked_managers.first).to include( + :id => manager.id, + :name => manager.name, + :age => manager.age, + :links => { :self => "http://foo.bar.com/#{manager.id}" } + ) + end + end + end + + end end end