add is_collection parameter to force corresponding serialization (#239)

* add is_collection parameter to force corresponding serialization

* add documentation for is_collection purpose, behavior
and notes re. default autodetect logic
This commit is contained in:
Oleksiy Babich 2018-07-04 05:35:06 +03:00 committed by Shishir Kakaraddi
parent af38b30179
commit ecb92f07f5
3 changed files with 72 additions and 3 deletions

View File

@ -261,6 +261,26 @@ hash = MovieSerializer.new([movie, movie], options).serializable_hash
json_string = MovieSerializer.new([movie, movie], options).serialized_json json_string = MovieSerializer.new([movie, movie], options).serialized_json
``` ```
#### Control Over Collection Serialization
You can use `is_collection` option to have better control over collection serialization.
If this option is not provided or `nil` autedetect logic is used to try understand
if provided resource is a single object or collection.
Autodetect logic is compatible with most DB toolkits (ActiveRecord, Sequel, etc.) but
**cannot** guarantee that single vs collection will be always detected properly.
```ruby
options[:is_collection]
```
was introduced to be able to have precise control this behavior
- `nil` or not provided: will try to autodetect single vs collection (please, see notes above)
- `true` will always treat input resource as *collection*
- `false` will always treat input resource as *single object*
### Caching ### Caching
Requires a `cache_key` method be defined on model: Requires a `cache_key` method be defined on model:

View File

@ -28,7 +28,7 @@ module FastJsonapi
end end
def serializable_hash def serializable_hash
return hash_for_collection if is_collection?(@resource) return hash_for_collection if is_collection?(@resource, @is_collection)
hash_for_one_record hash_for_one_record
end end
@ -75,6 +75,7 @@ module FastJsonapi
@known_included_objects = {} @known_included_objects = {}
@meta = options[:meta] @meta = options[:meta]
@links = options[:links] @links = options[:links]
@is_collection = options[:is_collection]
@params = options[:params] || {} @params = options[:params] || {}
raise ArgumentError.new("`params` option passed to serializer must be a hash") unless @params.is_a?(Hash) raise ArgumentError.new("`params` option passed to serializer must be a hash") unless @params.is_a?(Hash)
@ -84,8 +85,10 @@ module FastJsonapi
end end
end end
def is_collection?(resource) def is_collection?(resource, force_is_collection = nil)
resource.respond_to?(:each) && !resource.respond_to?(:each_pair) return force_is_collection unless force_is_collection.nil?
resource.respond_to?(:size) && !resource.respond_to?(:each_pair)
end end
class_methods do class_methods do

View File

@ -310,6 +310,52 @@ describe FastJsonapi::ObjectSerializer do
end end
end end
context 'when is_collection option present' do
subject { MovieSerializer.new(resource, is_collection_options).serializable_hash }
context 'autodetect' do
let(:is_collection_options) { {} }
context 'collection if no option present' do
let(:resource) { [movie] }
it { expect(subject[:data]).to be_a(Array) }
end
context 'single if no option present' do
let(:resource) { movie }
it { expect(subject[:data]).to be_a(Hash) }
end
end
context 'force is_collection to true' do
let(:is_collection_options) { { is_collection: true } }
context 'collection will pass' do
let(:resource) { [movie] }
it { expect(subject[:data]).to be_a(Array) }
end
context 'single will raise error' do
let(:resource) { movie }
it { expect { subject }.to raise_error(NoMethodError, /method(.*)each/) }
end
end
context 'force is_collection to false' do
let(:is_collection_options) { { is_collection: false } }
context 'collection will fail without id' do
let(:resource) { [movie] }
it { expect { subject }.to raise_error(FastJsonapi::MandatoryField, /id is a mandatory field/) }
end
context 'single will pass' do
let(:resource) { movie }
it { expect(subject[:data]).to be_a(Hash) }
end
end
end
context 'when optional attributes are determined by record data' do context 'when optional attributes are determined by record data' do
it 'returns optional attribute when attribute is included' do it 'returns optional attribute when attribute is included' do
movie.release_year = 2001 movie.release_year = 2001