From 587fb2c5fe3f221c1732ef5b10627b82eda10edd Mon Sep 17 00:00:00 2001 From: Henning Vogt Date: Tue, 15 Oct 2019 20:45:46 +0200 Subject: [PATCH] Add params to set_id block (#16) * Add params to set_id block arguments Pull request #331 added a block to the ObjectSerializer.set_id class method, which allows passing a block to the set_id method. Currently this block takes only one argument `record`: ``` set_id do |record| "#{record.name.downcase}-#{record.id}" end ``` This PR adds another argument `params` to the block: ``` set id do |record, params| params[:admin] ? record.id : "#{record.name.downcase}-#{record.id}" end ``` This customization can be useful in situation where we serve different clients that may need different IDs. One nice side effect is also that the `set_id` method has the same method signature as the `attribute` method. * Update the README --- README.md | 12 +++++++++--- lib/fast_jsonapi/serialization_core.rb | 10 +++++----- spec/lib/object_serializer_class_methods_spec.rb | 11 +++++++++-- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index b18d055..b9cd186 100644 --- a/README.md +++ b/README.md @@ -381,13 +381,19 @@ related to a current authenticated user. The `options[:params]` value covers the cases by allowing you to pass in a hash of additional parameters necessary for your use case. -Leveraging the new params is easy, when you define a custom attribute or relationship with a -block you opt-in to using params by adding it as a block parameter. +Leveraging the new params is easy, when you define a custom id, attribute or +relationship with a block you opt-in to using params by adding it as a block +parameter. ```ruby class MovieSerializer include FastJsonapi::ObjectSerializer + set_id do |movie, params| + # in here, params is a hash containing the `:admin` key + params[:admin] ? movie.owner_id : "movie-#{movie.id}" + end + attributes :name, :year attribute :can_view_early do |movie, params| # in here, params is a hash containing the `:current_user` key @@ -539,7 +545,7 @@ Option | Purpose | Example ------------ | ------------- | ------------- set_type | Type name of Object | ```set_type :movie ``` key | Key of Object | ```belongs_to :owner, key: :user ``` -set_id | ID of Object | ```set_id :owner_id ``` or ```set_id { \|record\| "#{record.name.downcase}-#{record.id}" }``` +set_id | ID of Object | ```set_id :owner_id ``` or ```set_id { \|record, params\| params[:admin] ? record.id : "#{record.name.downcase}-#{record.id}" }``` cache_options | Hash to enable caching and set cache length | ```cache_options enabled: true, cache_length: 12.hours, race_condition_ttl: 10.seconds``` id_method_name | Set custom method name to get ID of an object (If block is provided for the relationship, `id_method_name` is invoked on the return value of the block instead of the resource object) | ```has_many :locations, id_method_name: :place_ids ``` object_method_name | Set custom method name to get related objects | ```has_many :locations, object_method_name: :places ``` diff --git a/lib/fast_jsonapi/serialization_core.rb b/lib/fast_jsonapi/serialization_core.rb index 1c9a3bc..73d3234 100644 --- a/lib/fast_jsonapi/serialization_core.rb +++ b/lib/fast_jsonapi/serialization_core.rb @@ -69,7 +69,7 @@ module FastJsonapi def record_hash(record, fieldset, includes_list, params = {}) if cached record_hash = Rails.cache.fetch(record.cache_key, expires_in: cache_length, race_condition_ttl: race_condition_ttl) do - temp_hash = id_hash(id_from_record(record), record_type, true) + temp_hash = id_hash(id_from_record(record, params), record_type, true) temp_hash[:attributes] = attributes_hash(record, fieldset, params) if attributes_to_serialize.present? temp_hash[:relationships] = {} temp_hash[:relationships] = relationships_hash(record, cachable_relationships_to_serialize, fieldset, includes_list, params) if cachable_relationships_to_serialize.present? @@ -80,7 +80,7 @@ module FastJsonapi 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 = id_hash(id_from_record(record, params), record_type, true) record_hash[:attributes] = attributes_hash(record, fieldset, params) if attributes_to_serialize.present? record_hash[:relationships] = relationships_hash(record, nil, fieldset, includes_list, params) if relationships_to_serialize.present? record_hash[:links] = links_hash(record, params) if data_links.present? @@ -89,8 +89,8 @@ module FastJsonapi end end - def id_from_record(record) - return record_id.call(record) if record_id.is_a?(Proc) + def id_from_record(record, params) + return record_id.call(record, params) if record_id.is_a?(Proc) return record.send(record_id) if record_id raise MandatoryField, 'id is a mandatory field in the jsonapi spec' unless record.respond_to?(:id) record.id @@ -146,7 +146,7 @@ module FastJsonapi included_records.concat(serializer_records) unless serializer_records.empty? end - code = "#{record_type}_#{serializer.id_from_record(inc_obj)}" + code = "#{record_type}_#{serializer.id_from_record(inc_obj, params)}" next if known_included_objects.key?(code) known_included_objects[code] = inc_obj diff --git a/spec/lib/object_serializer_class_methods_spec.rb b/spec/lib/object_serializer_class_methods_spec.rb index 6fe4718..796628b 100644 --- a/spec/lib/object_serializer_class_methods_spec.rb +++ b/spec/lib/object_serializer_class_methods_spec.rb @@ -193,7 +193,10 @@ describe FastJsonapi::ObjectSerializer do end describe '#set_id' do - subject(:serializable_hash) { MovieSerializer.new(resource).serializable_hash } + let(:params) { {} } + subject(:serializable_hash) do + MovieSerializer.new(resource, { params: params }).serializable_hash + end context 'method name' do before do @@ -223,8 +226,12 @@ describe FastJsonapi::ObjectSerializer do end context 'with block' do + let(:params) { { prefix: 'movie' } } + before do - MovieSerializer.set_id { |record| "movie-#{record.owner_id}" } + MovieSerializer.set_id do |record, params| + "#{params[:prefix]}-#{record.owner_id}" + end end after do