Merge branch 'dev' into add-links-option-to-relationship-serializer
This commit is contained in:
commit
100f850416
20
README.md
20
README.md
@ -275,6 +275,18 @@ This will create a `self` reference for the relationship, and a `related` link f
|
|||||||
end
|
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
|
||||||
|
meta do |movie|
|
||||||
|
{
|
||||||
|
years_since_release: Date.current.year - movie.year
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
### Compound Document
|
### Compound Document
|
||||||
|
|
||||||
Support for top-level and nested included associations through ` options[:include] `.
|
Support for top-level and nested included associations through ` options[:include] `.
|
||||||
@ -381,15 +393,15 @@ class MovieSerializer
|
|||||||
include FastJsonapi::ObjectSerializer
|
include FastJsonapi::ObjectSerializer
|
||||||
|
|
||||||
attributes :name, :year
|
attributes :name, :year
|
||||||
attribute :release_year, if: Proc.new do |record|
|
attribute :release_year, if: Proc.new { |record|
|
||||||
# Release year will only be serialized if it's greater than 1990
|
# Release year will only be serialized if it's greater than 1990
|
||||||
record.release_year > 1990
|
record.release_year > 1990
|
||||||
end
|
}
|
||||||
|
|
||||||
attribute :director, if: Proc.new do |record, params|
|
attribute :director, if: Proc.new { |record, params|
|
||||||
# The director will be serialized only if the :admin key of params is true
|
# The director will be serialized only if the :admin key of params is true
|
||||||
params && params[:admin] == true
|
params && params[:admin] == true
|
||||||
end
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
# ...
|
# ...
|
||||||
|
@ -120,6 +120,7 @@ module FastJsonapi
|
|||||||
subclass.data_links = data_links
|
subclass.data_links = data_links
|
||||||
subclass.cached = cached
|
subclass.cached = cached
|
||||||
subclass.set_type(subclass.reflected_record_type) if subclass.reflected_record_type
|
subclass.set_type(subclass.reflected_record_type) if subclass.reflected_record_type
|
||||||
|
subclass.meta_to_serialize = meta_to_serialize
|
||||||
end
|
end
|
||||||
|
|
||||||
def reflected_record_type
|
def reflected_record_type
|
||||||
@ -218,6 +219,10 @@ module FastJsonapi
|
|||||||
add_relationship(relationship)
|
add_relationship(relationship)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def meta(&block)
|
||||||
|
self.meta_to_serialize = block
|
||||||
|
end
|
||||||
|
|
||||||
def create_relationship(base_key, relationship_type, options, block)
|
def create_relationship(base_key, relationship_type, options, block)
|
||||||
name = base_key.to_sym
|
name = base_key.to_sym
|
||||||
if relationship_type == :has_many
|
if relationship_type == :has_many
|
||||||
@ -232,7 +237,11 @@ module FastJsonapi
|
|||||||
Relationship.new(
|
Relationship.new(
|
||||||
key: options[:key] || run_key_transform(base_key),
|
key: options[:key] || run_key_transform(base_key),
|
||||||
name: name,
|
name: name,
|
||||||
id_method_name: options[:id_method_name] || "#{base_serialization_key}#{id_postfix}".to_sym,
|
id_method_name: compute_id_method_name(
|
||||||
|
options[:id_method_name],
|
||||||
|
"#{base_serialization_key}#{id_postfix}".to_sym,
|
||||||
|
block
|
||||||
|
),
|
||||||
record_type: options[:record_type] || run_key_transform(base_key_sym),
|
record_type: options[:record_type] || run_key_transform(base_key_sym),
|
||||||
object_method_name: options[:object_method_name] || name,
|
object_method_name: options[:object_method_name] || name,
|
||||||
object_block: block,
|
object_block: block,
|
||||||
@ -245,6 +254,14 @@ module FastJsonapi
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def compute_id_method_name(custom_id_method_name, id_method_name_from_relationship, block)
|
||||||
|
if block.present?
|
||||||
|
custom_id_method_name || :id
|
||||||
|
else
|
||||||
|
custom_id_method_name || id_method_name_from_relationship
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def compute_serializer_name(serializer_key)
|
def compute_serializer_name(serializer_key)
|
||||||
return serializer_key unless serializer_key.is_a? Symbol
|
return serializer_key unless serializer_key.is_a? Symbol
|
||||||
namespace = self.name.gsub(/()?\w+Serializer$/, '')
|
namespace = self.name.gsub(/()?\w+Serializer$/, '')
|
||||||
|
@ -89,13 +89,11 @@ module FastJsonapi
|
|||||||
end
|
end
|
||||||
|
|
||||||
def fetch_id(record, params)
|
def fetch_id(record, params)
|
||||||
unless object_block.nil?
|
if object_block.present?
|
||||||
object = object_block.call(record, params)
|
object = object_block.call(record, params)
|
||||||
|
return object.map { |item| item.public_send(id_method_name) } if object.respond_to? :map
|
||||||
return object.map(&:id) if object.respond_to? :map
|
return object.try(id_method_name)
|
||||||
return object.try(:id)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
record.public_send(id_method_name)
|
record.public_send(id_method_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -21,7 +21,8 @@ module FastJsonapi
|
|||||||
:cache_length,
|
:cache_length,
|
||||||
:race_condition_ttl,
|
:race_condition_ttl,
|
||||||
:cached,
|
:cached,
|
||||||
:data_links
|
:data_links,
|
||||||
|
:meta_to_serialize
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -57,6 +58,10 @@ module FastJsonapi
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def meta_hash(record, params = {})
|
||||||
|
meta_to_serialize.call(record, params)
|
||||||
|
end
|
||||||
|
|
||||||
def record_hash(record, fieldset, params = {})
|
def record_hash(record, fieldset, 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
|
||||||
@ -67,13 +72,15 @@ module FastJsonapi
|
|||||||
temp_hash[:links] = links_hash(record, params) if data_links.present?
|
temp_hash[:links] = links_hash(record, params) if data_links.present?
|
||||||
temp_hash
|
temp_hash
|
||||||
end
|
end
|
||||||
record_hash[:relationships] = record_hash[:relationships].merge(relationships_hash(record, uncachable_relationships_to_serialize, params)) if uncachable_relationships_to_serialize.present?
|
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
|
record_hash
|
||||||
else
|
else
|
||||||
record_hash = id_hash(id_from_record(record), record_type, true)
|
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[: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[: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[:links] = links_hash(record, params) if data_links.present?
|
||||||
|
record_hash[:meta] = meta_hash(record, params) if meta_to_serialize.present?
|
||||||
record_hash
|
record_hash
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -123,7 +130,7 @@ module FastJsonapi
|
|||||||
|
|
||||||
included_objects.each do |inc_obj|
|
included_objects.each do |inc_obj|
|
||||||
if remaining_items(items)
|
if remaining_items(items)
|
||||||
serializer_records = serializer.get_included_records(inc_obj, remaining_items(items), known_included_objects, fieldsets)
|
serializer_records = serializer.get_included_records(inc_obj, remaining_items(items), known_included_objects, fieldsets, params)
|
||||||
included_records.concat(serializer_records) unless serializer_records.empty?
|
included_records.concat(serializer_records) unless serializer_records.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -87,6 +87,31 @@ describe FastJsonapi::ObjectSerializer do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#has_many with block and id_method_name' do
|
||||||
|
before do
|
||||||
|
MovieSerializer.has_many(:awards, id_method_name: :imdb_award_id) do |movie|
|
||||||
|
movie.actors.map(&:awards).flatten
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
after do
|
||||||
|
MovieSerializer.relationships_to_serialize.delete(:awards)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'awards is not included' do
|
||||||
|
subject(:hash) { MovieSerializer.new(movie).serializable_hash }
|
||||||
|
|
||||||
|
it 'returns correct hash where id is obtained from the method specified via `id_method_name`' do
|
||||||
|
expected_award_data = movie.actors.map(&:awards).flatten.map do |actor|
|
||||||
|
{ id: actor.imdb_award_id.to_s, type: actor.class.name.downcase.to_sym }
|
||||||
|
end
|
||||||
|
serialized_award_data = hash[:data][:relationships][:awards][:data]
|
||||||
|
|
||||||
|
expect(serialized_award_data).to eq(expected_award_data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#belongs_to' do
|
describe '#belongs_to' do
|
||||||
subject(:relationship) { MovieSerializer.relationships_to_serialize[:area] }
|
subject(:relationship) { MovieSerializer.relationships_to_serialize[:area] }
|
||||||
|
|
||||||
@ -249,6 +274,34 @@ describe FastJsonapi::ObjectSerializer do
|
|||||||
end
|
end
|
||||||
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
|
describe '#link' do
|
||||||
subject(:serializable_hash) { MovieSerializer.new(movie).serializable_hash }
|
subject(:serializable_hash) { MovieSerializer.new(movie).serializable_hash }
|
||||||
|
|
||||||
|
@ -310,6 +310,23 @@ describe FastJsonapi::ObjectSerializer do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when serializing included, params should be available in any serializer' do
|
||||||
|
subject(:serializable_hash) do
|
||||||
|
options = {}
|
||||||
|
options[:include] = [:"actors.awards"]
|
||||||
|
options[:params] = { include_award_year: true }
|
||||||
|
MovieSerializer.new(movie, options).serializable_hash
|
||||||
|
end
|
||||||
|
let(:actor) { movie.actors.first }
|
||||||
|
let(:award) { actor.awards.first }
|
||||||
|
let(:year) { award.year }
|
||||||
|
|
||||||
|
it 'passes params to deeply nested includes' do
|
||||||
|
expect(year).to_not be_blank
|
||||||
|
expect(serializable_hash[:included][0][:attributes][:year]).to eq year
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'when is_collection option present' do
|
context 'when is_collection option present' do
|
||||||
subject { MovieSerializer.new(resource, is_collection_options).serializable_hash }
|
subject { MovieSerializer.new(resource, is_collection_options).serializable_hash }
|
||||||
|
|
||||||
|
@ -84,6 +84,8 @@ RSpec.shared_context 'movie class' do
|
|||||||
a.id = i
|
a.id = i
|
||||||
a.title = "Test Award #{i}"
|
a.title = "Test Award #{i}"
|
||||||
a.actor_id = id
|
a.actor_id = id
|
||||||
|
a.imdb_award_id = i * 10
|
||||||
|
a.year = 1990 + i
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -114,7 +116,7 @@ RSpec.shared_context 'movie class' do
|
|||||||
end
|
end
|
||||||
|
|
||||||
class Award
|
class Award
|
||||||
attr_accessor :id, :title, :actor_id
|
attr_accessor :id, :title, :actor_id, :year, :imdb_award_id
|
||||||
end
|
end
|
||||||
|
|
||||||
class State
|
class State
|
||||||
@ -229,6 +231,11 @@ RSpec.shared_context 'movie class' do
|
|||||||
class AwardSerializer
|
class AwardSerializer
|
||||||
include FastJsonapi::ObjectSerializer
|
include FastJsonapi::ObjectSerializer
|
||||||
attributes :id, :title
|
attributes :id, :title
|
||||||
|
attribute :year, if: Proc.new { |record, params|
|
||||||
|
params[:include_award_year].present? ?
|
||||||
|
params[:include_award_year] :
|
||||||
|
false
|
||||||
|
}
|
||||||
belongs_to :actor
|
belongs_to :actor
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user