diff --git a/README.md b/README.md index d7032c1..86ca19d 100644 --- a/README.md +++ b/README.md @@ -245,6 +245,23 @@ class MovieSerializer end ``` +### Meta Per Resource + +For every resource in the collection, you can include a meta object containing non-standard meta-information about a resource that can not be represented as an attribute or relationship. + + +```ruby +class MovieSerializer + include FastJsonapi::ObjectSerializer + + meta do |movie| + { + years_since_release: Date.current.year - movie.year + } + 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 d6015c5..28b4390 100644 --- a/lib/fast_jsonapi/object_serializer.rb +++ b/lib/fast_jsonapi/object_serializer.rb @@ -120,6 +120,7 @@ module FastJsonapi subclass.data_links = data_links subclass.cached = cached subclass.set_type(subclass.reflected_record_type) if subclass.reflected_record_type + subclass.meta_to_serialize = meta_to_serialize end def reflected_record_type @@ -218,6 +219,10 @@ module FastJsonapi add_relationship(relationship) end + def meta(&block) + self.meta_to_serialize = block + end + def create_relationship(base_key, relationship_type, options, block) name = base_key.to_sym if relationship_type == :has_many diff --git a/lib/fast_jsonapi/serialization_core.rb b/lib/fast_jsonapi/serialization_core.rb index 0bfeaad..8598fe0 100644 --- a/lib/fast_jsonapi/serialization_core.rb +++ b/lib/fast_jsonapi/serialization_core.rb @@ -21,7 +21,8 @@ module FastJsonapi :cache_length, :race_condition_ttl, :cached, - :data_links + :data_links, + :meta_to_serialize end end @@ -57,6 +58,10 @@ module FastJsonapi end end + def meta_hash(record, params = {}) + meta_to_serialize.call(record, params) + end + def record_hash(record, fieldset, params = {}) if cached record_hash = Rails.cache.fetch(record.cache_key, expires_in: cache_length, race_condition_ttl: race_condition_ttl) do @@ -68,12 +73,14 @@ module FastJsonapi temp_hash end record_hash[:relationships] = record_hash[:relationships].merge(relationships_hash(record, uncachable_relationships_to_serialize, fieldset, params)) if uncachable_relationships_to_serialize.present? + record_hash[:meta] = meta_hash(record, params) if meta_to_serialize.present? record_hash else record_hash = id_hash(id_from_record(record), record_type, true) record_hash[:attributes] = attributes_hash(record, fieldset, params) if attributes_to_serialize.present? record_hash[:relationships] = relationships_hash(record, nil, fieldset, params) if relationships_to_serialize.present? record_hash[:links] = links_hash(record, params) if data_links.present? + record_hash[:meta] = meta_hash(record, params) if meta_to_serialize.present? record_hash end end diff --git a/spec/lib/object_serializer_class_methods_spec.rb b/spec/lib/object_serializer_class_methods_spec.rb index 33138d5..397ace5 100644 --- a/spec/lib/object_serializer_class_methods_spec.rb +++ b/spec/lib/object_serializer_class_methods_spec.rb @@ -274,6 +274,34 @@ describe FastJsonapi::ObjectSerializer do end end + describe '#meta' do + subject(:serializable_hash) { MovieSerializer.new(movie).serializable_hash } + + before do + movie.release_year = 2008 + MovieSerializer.meta do |movie| + { + years_since_release: year_since_release_calculator(movie.release_year) + } + end + end + + after do + movie.release_year = nil + MovieSerializer.meta_to_serialize = nil + end + + it 'returns correct hash when serializable_hash is called' do + expect(serializable_hash[:data][:meta]).to eq ({ years_since_release: year_since_release_calculator(movie.release_year) }) + end + + private + + def year_since_release_calculator(release_year) + Date.current.year - release_year + end + end + describe '#link' do subject(:serializable_hash) { MovieSerializer.new(movie).serializable_hash }