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
This commit is contained in:
Henning Vogt 2019-10-15 20:45:46 +02:00 committed by Kevin Pheasey
parent 691c8ac632
commit 587fb2c5fe
3 changed files with 23 additions and 10 deletions

View File

@ -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 cases by allowing you to pass in a hash of additional parameters necessary for
your use case. your use case.
Leveraging the new params is easy, when you define a custom attribute or relationship with a Leveraging the new params is easy, when you define a custom id, attribute or
block you opt-in to using params by adding it as a block parameter. relationship with a block you opt-in to using params by adding it as a block
parameter.
```ruby ```ruby
class MovieSerializer class MovieSerializer
include FastJsonapi::ObjectSerializer 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 attributes :name, :year
attribute :can_view_early do |movie, params| attribute :can_view_early do |movie, params|
# in here, params is a hash containing the `:current_user` key # 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 ``` set_type | Type name of Object | ```set_type :movie ```
key | Key of Object | ```belongs_to :owner, key: :user ``` 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``` 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 ``` 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 ``` object_method_name | Set custom method name to get related objects | ```has_many :locations, object_method_name: :places ```

View File

@ -69,7 +69,7 @@ module FastJsonapi
def record_hash(record, fieldset, includes_list, params = {}) def record_hash(record, fieldset, includes_list, params = {})
if cached if cached
record_hash = Rails.cache.fetch(record.cache_key, expires_in: cache_length, race_condition_ttl: race_condition_ttl) do 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[:attributes] = attributes_hash(record, fieldset, params) if attributes_to_serialize.present?
temp_hash[:relationships] = {} temp_hash[:relationships] = {}
temp_hash[:relationships] = relationships_hash(record, cachable_relationships_to_serialize, fieldset, includes_list, params) if cachable_relationships_to_serialize.present? 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[:meta] = meta_hash(record, params) if meta_to_serialize.present?
record_hash record_hash
else 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[: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[: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? record_hash[:links] = links_hash(record, params) if data_links.present?
@ -89,8 +89,8 @@ module FastJsonapi
end end
end end
def id_from_record(record) def id_from_record(record, params)
return record_id.call(record) if record_id.is_a?(Proc) return record_id.call(record, params) if record_id.is_a?(Proc)
return record.send(record_id) if record_id return record.send(record_id) if record_id
raise MandatoryField, 'id is a mandatory field in the jsonapi spec' unless record.respond_to?(:id) raise MandatoryField, 'id is a mandatory field in the jsonapi spec' unless record.respond_to?(:id)
record.id record.id
@ -146,7 +146,7 @@ module FastJsonapi
included_records.concat(serializer_records) unless serializer_records.empty? included_records.concat(serializer_records) unless serializer_records.empty?
end 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) next if known_included_objects.key?(code)
known_included_objects[code] = inc_obj known_included_objects[code] = inc_obj

View File

@ -193,7 +193,10 @@ describe FastJsonapi::ObjectSerializer do
end end
describe '#set_id' do 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 context 'method name' do
before do before do
@ -223,8 +226,12 @@ describe FastJsonapi::ObjectSerializer do
end end
context 'with block' do context 'with block' do
let(:params) { { prefix: 'movie' } }
before do before do
MovieSerializer.set_id { |record| "movie-#{record.owner_id}" } MovieSerializer.set_id do |record, params|
"#{params[:prefix]}-#{record.owner_id}"
end
end end
after do after do