diff --git a/README.md b/README.md index a03e1a8..b9fe2ba 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 7f740c8..4441cc9 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 6ec069a..43ad4e3 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, 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 3c477c3..b8a1eea 100644 --- a/spec/lib/object_serializer_class_methods_spec.rb +++ b/spec/lib/object_serializer_class_methods_spec.rb @@ -249,6 +249,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 }