ability to customize rendering of attributes via a block (#54)

* add hash benchmarking to performance tests

* Add missing attribute in README example

* Disable GC before doing performance test

* Enable oj to AM for fair benchmark test

* ability to customize rendering of attributes via a block

* fixed attribute render spec

* minimized specs to specifially test this feature

* Update README to include attribute definitions

* Fixed syntax error

* Fixed merge issues
This commit is contained in:
Christopher Sansone 2018-02-09 11:59:07 -05:00 committed by Shishir Kakaraddi
parent 6d516c217c
commit b30a53bc5f
5 changed files with 68 additions and 4 deletions

View File

@ -155,6 +155,45 @@ set_key_transform :dash # "some_key" => "some-key"
set_key_transform :underscore # "some_key" => "some_key"
```
### Attributes
Attributes are defined in FastJsonapi using the `attributes` method. This method is also aliased as `attribute`, which is useful when defining a single attribute.
By default, attributes are read directly from the model property of the same name. In this example, `name` is expected to be a property of the object being serialized:
```ruby
class MovieSerializer
include FastJsonapi::ObjectSerializer
attribute :name
end
```
Custom attributes that must be serialized but do not exist on the model can be declared using Ruby block syntax:
```ruby
class MovieSerializer
include FastJsonapi::ObjectSerializer
attributes :name, :year
attribute :name_with_year do |object|
"#{object.name} (#{object.year})"
end
end
```
The block syntax can also be used to override the property on the object:
```ruby
class MovieSerializer
include FastJsonapi::ObjectSerializer
attribute :name do |object|
"#{object.name} Part 2"
end
end
```
### Compound Document
Support for top-level included member through ` options[:include] `.

View File

@ -140,16 +140,18 @@ module FastJsonapi
self.cache_length = cache_options[:cache_length] || 5.minutes
end
def attributes(*attributes_list)
def attributes(*attributes_list, &block)
attributes_list = attributes_list.first if attributes_list.first.class.is_a?(Array)
self.attributes_to_serialize = {} if self.attributes_to_serialize.nil?
attributes_list.each do |attr_name|
method_name = attr_name
key = run_key_transform(method_name)
attributes_to_serialize[key] = method_name
attributes_to_serialize[key] = block || method_name
end
end
alias_method :attribute, :attributes
def add_relationship(name, relationship)
self.relationships_to_serialize = {} if relationships_to_serialize.nil?
self.cachable_relationships_to_serialize = {} if cachable_relationships_to_serialize.nil?

View File

@ -52,8 +52,8 @@ module FastJsonapi
end
def attributes_hash(record)
attributes_to_serialize.each_with_object({}) do |(key, method_name), attr_hash|
attr_hash[key] = record.public_send(method_name)
attributes_to_serialize.each_with_object({}) do |(key, method), attr_hash|
attr_hash[key] = method.is_a?(Proc) ? method.call(record) : record.public_send(method)
end
end

View File

@ -0,0 +1,13 @@
require 'spec_helper'
describe FastJsonapi::ObjectSerializer do
include_context 'movie class'
context 'when including attribute blocks' do
it 'returns correct hash when serializable_hash is called' do
serializable_hash = MovieSerializerWithAttributeBlock.new([movie]).serializable_hash
expect(serializable_hash[:data][0][:attributes][:name]).to eq movie.name
expect(serializable_hash[:data][0][:attributes][:title_with_year]).to eq "#{movie.name} (#{movie.release_year})"
end
end
end

View File

@ -96,6 +96,15 @@ RSpec.shared_context 'movie class' do
attributes :name
end
class MovieSerializerWithAttributeBlock
include FastJsonapi::ObjectSerializer
set_type :movie
attributes :name, :release_year
attribute :title_with_year do |record|
"#{record.name} (#{record.release_year})"
end
end
class SupplierSerializer
include FastJsonapi::ObjectSerializer
set_type :supplier
@ -140,6 +149,7 @@ RSpec.shared_context 'movie class' do
ActorSerializer
MovieType
MovieTypeSerializer
MovieSerializerWithAttributeBlock
AppName::V1::MovieSerializer
MovieStruct
ActorStruct