From dd7f5ba415eaedc1b5625d1c701c0f39fe444e24 Mon Sep 17 00:00:00 2001 From: mperice Date: Tue, 7 Jul 2020 16:22:25 +0200 Subject: [PATCH] Add optional meta field to relationships (#99) (#100) * Add optional meta field to relationships (#99) * Fix Rubocop's warnings. * Minor syntax corrections. --- README.md | 17 +++++++++++++++++ lib/fast_jsonapi/object_serializer.rb | 1 + lib/fast_jsonapi/relationship.rb | 16 ++++++++++++++-- spec/fixtures/movie.rb | 1 + spec/integration/relationships_spec.rb | 7 +++++++ 5 files changed, 40 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5ac3b13..874ac5b 100644 --- a/README.md +++ b/README.md @@ -317,6 +317,23 @@ class MovieSerializer end ``` +#### Meta on a Relationship + +You can specify [relationship meta](http://jsonapi.org/format/#document-resource-object-relationships) by using the `meta:` option on the serializer. Relationship meta in JSON API is useful if you wish to provide non-standard meta-information about the relationship. + +Meta can be defined either by passing a static hash or by using Proc to the `meta` key. In the latter case, the record and any params passed to the serializer are available inside the Proc as the first and second parameters, respectively. + + +```ruby +class MovieSerializer + include JSONAPI::Serializer + + has_many :actors, meta: Proc.new do |movie_record, params| + { count: movie_record.actors.length } + end +end +``` + ### Compound Document Support for top-level and nested included associations through `options[:include]`. diff --git a/lib/fast_jsonapi/object_serializer.rb b/lib/fast_jsonapi/object_serializer.rb index dce029d..dfc0871 100644 --- a/lib/fast_jsonapi/object_serializer.rb +++ b/lib/fast_jsonapi/object_serializer.rb @@ -283,6 +283,7 @@ module FastJsonapi polymorphic: polymorphic, conditional_proc: options[:if], transform_method: @transform_method, + meta: options[:meta], links: options[:links], lazy_load_data: options[:lazy_load_data] ) diff --git a/lib/fast_jsonapi/relationship.rb b/lib/fast_jsonapi/relationship.rb index f5d299e..31e804e 100644 --- a/lib/fast_jsonapi/relationship.rb +++ b/lib/fast_jsonapi/relationship.rb @@ -1,6 +1,6 @@ module FastJsonapi class Relationship - attr_reader :owner, :key, :name, :id_method_name, :record_type, :object_method_name, :object_block, :serializer, :relationship_type, :cached, :polymorphic, :conditional_proc, :transform_method, :links, :lazy_load_data + attr_reader :owner, :key, :name, :id_method_name, :record_type, :object_method_name, :object_block, :serializer, :relationship_type, :cached, :polymorphic, :conditional_proc, :transform_method, :links, :meta, :lazy_load_data def initialize( owner:, @@ -17,6 +17,7 @@ module FastJsonapi conditional_proc:, transform_method:, links:, + meta:, lazy_load_data: false ) @owner = owner @@ -33,6 +34,7 @@ module FastJsonapi @conditional_proc = conditional_proc @transform_method = transform_method @links = links || {} + @meta = meta || {} @lazy_load_data = lazy_load_data @record_types_for = {} @serializers_for_name = {} @@ -44,6 +46,8 @@ module FastJsonapi output_hash[key] = {} output_hash[key][:data] = ids_hash_from_record_and_relationship(record, serialization_params) || empty_case unless lazy_load_data && !included + + add_meta_hash(record, serialization_params, output_hash) if meta.present? add_links_hash(record, serialization_params, output_hash) if links.present? end end @@ -146,11 +150,19 @@ module FastJsonapi record.public_send(links) else links.each_with_object({}) do |(key, method), hash| - Link.new(key: key, method: method).serialize(record, params, hash)\ + Link.new(key: key, method: method).serialize(record, params, hash) end end end + def add_meta_hash(record, params, output_hash) + output_hash[key][:meta] = if meta.is_a?(Proc) + FastJsonapi.call_proc(meta, record, params) + else + meta + end + end + def run_key_transform(input) if transform_method.present? input.to_s.send(*transform_method).to_sym diff --git a/spec/fixtures/movie.rb b/spec/fixtures/movie.rb index ee3da5f..3156443 100644 --- a/spec/fixtures/movie.rb +++ b/spec/fixtures/movie.rb @@ -66,6 +66,7 @@ class MovieSerializer has_many( :actors, + meta: proc { |record, _| { count: record.actors.length } }, links: { actors_self: :url, related: ->(obj) { obj.url(obj) } diff --git a/spec/integration/relationships_spec.rb b/spec/integration/relationships_spec.rb index b545ae8..840ae8e 100644 --- a/spec/integration/relationships_spec.rb +++ b/spec/integration/relationships_spec.rb @@ -59,6 +59,13 @@ RSpec.describe FastJsonapi::ObjectSerializer do ) end + describe 'has relationship meta' do + it do + expect(serialized['data']['relationships']['actors']) + .to have_meta('count' => movie.actors.length) + end + end + context 'with include' do let(:params) do { include: [:actors] }