From bad004fd4244cd6f89b441f291d69ca6ef46b251 Mon Sep 17 00:00:00 2001 From: Trevor Hinesley Date: Thu, 21 Jun 2018 14:50:51 -0500 Subject: [PATCH] Allow conditional attributes --- lib/fast_jsonapi/object_serializer.rb | 9 +++++++- lib/fast_jsonapi/serialization_core.rb | 11 ++++++++- spec/lib/object_serializer_spec.rb | 32 ++++++++++++++++++++++++++ spec/shared/contexts/movie_context.rb | 14 +++++++++++ 4 files changed, 64 insertions(+), 2 deletions(-) diff --git a/lib/fast_jsonapi/object_serializer.rb b/lib/fast_jsonapi/object_serializer.rb index 4dea074..895fa8c 100644 --- a/lib/fast_jsonapi/object_serializer.rb +++ b/lib/fast_jsonapi/object_serializer.rb @@ -149,11 +149,18 @@ module FastJsonapi def attributes(*attributes_list, &block) attributes_list = attributes_list.first if attributes_list.first.class.is_a?(Array) + options = attributes_list.last.is_a?(Hash) ? attributes_list.pop : {} self.attributes_to_serialize = {} if self.attributes_to_serialize.nil? + self.optional_attributes_to_serialize = {} if self.optional_attributes_to_serialize.nil? + attributes_list.each do |attr_name| method_name = attr_name key = run_key_transform(method_name) - attributes_to_serialize[key] = block || method_name + if options[:if].present? + optional_attributes_to_serialize[key] = [method_name, options[:if]] + else + attributes_to_serialize[key] = block || method_name + end end end diff --git a/lib/fast_jsonapi/serialization_core.rb b/lib/fast_jsonapi/serialization_core.rb index 668aebe..f838dff 100644 --- a/lib/fast_jsonapi/serialization_core.rb +++ b/lib/fast_jsonapi/serialization_core.rb @@ -12,6 +12,7 @@ module FastJsonapi included do class << self attr_accessor :attributes_to_serialize, + :optional_attributes_to_serialize, :relationships_to_serialize, :cachable_relationships_to_serialize, :uncachable_relationships_to_serialize, @@ -73,13 +74,21 @@ module FastJsonapi end def attributes_hash(record, params = {}) - attributes_to_serialize.each_with_object({}) do |(key, method), attr_hash| + attributes = attributes_to_serialize.each_with_object({}) do |(key, method), attr_hash| attr_hash[key] = if method.is_a?(Proc) method.arity == 1 ? method.call(record) : method.call(record, params) else record.public_send(method) end end + + self.optional_attributes_to_serialize = {} if self.optional_attributes_to_serialize.nil? + optional_attributes_to_serialize.each do |key, details| + method_name, check_proc = details + attributes[key] = record.send(method_name) if check_proc.call(record, params) + end + + attributes end def relationships_hash(record, relationships = nil, params = {}) diff --git a/spec/lib/object_serializer_spec.rb b/spec/lib/object_serializer_spec.rb index 7941f66..46d0cea 100644 --- a/spec/lib/object_serializer_spec.rb +++ b/spec/lib/object_serializer_spec.rb @@ -309,4 +309,36 @@ describe FastJsonapi::ObjectSerializer do expect(serializable_hash[:included][0][:links][:self]).to eq url end end + + context 'when optional attributes are determined by record data' do + it 'returns optional attribute when attribute is included' do + movie.release_year = 2001 + json = MovieOptionalRecordDataSerializer.new(movie).serialized_json + serializable_hash = JSON.parse(json) + expect(serializable_hash['data']['attributes']['release_year']).to eq movie.release_year + end + + it "doesn't return optional attribute when attribute is not included" do + movie.release_year = 1970 + json = MovieOptionalRecordDataSerializer.new(movie).serialized_json + serializable_hash = JSON.parse(json) + expect(serializable_hash['data']['attributes'].has_key?('release_year')).to be_falsey + end + end + + context 'when optional attributes are determined by params data' do + it 'returns optional attribute when attribute is included' do + movie.director = 'steven spielberg' + json = MovieOptionalParamsDataSerializer.new(movie, { params: { admin: true }}).serialized_json + serializable_hash = JSON.parse(json) + expect(serializable_hash['data']['attributes']['director']).to eq 'steven spielberg' + end + + it "doesn't return optional attribute when attribute is not included" do + movie.director = 'steven spielberg' + json = MovieOptionalParamsDataSerializer.new(movie, { params: { admin: false }}).serialized_json + serializable_hash = JSON.parse(json) + expect(serializable_hash['data']['attributes'].has_key?('director')).to be_falsey + end + end end diff --git a/spec/shared/contexts/movie_context.rb b/spec/shared/contexts/movie_context.rb index a73e869..4df6a91 100644 --- a/spec/shared/contexts/movie_context.rb +++ b/spec/shared/contexts/movie_context.rb @@ -278,6 +278,20 @@ RSpec.shared_context 'movie class' do set_type :account belongs_to :supplier end + + class MovieOptionalRecordDataSerializer + include FastJsonapi::ObjectSerializer + set_type :movie + attributes :name + attribute :release_year, if: Proc.new { |record| record.release_year >= 2000 } + end + + class MovieOptionalParamsDataSerializer + include FastJsonapi::ObjectSerializer + set_type :movie + attributes :name + attribute :director, if: Proc.new { |record, params| params && params[:admin] == true } + end end