Skip to content

Commit b30a53b

Browse files
christophersansoneshishirmk
authored andcommitted
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
1 parent 6d516c2 commit b30a53b

5 files changed

Lines changed: 68 additions & 4 deletions

File tree

README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,45 @@ set_key_transform :dash # "some_key" => "some-key"
155155
set_key_transform :underscore # "some_key" => "some_key"
156156
```
157157

158+
### Attributes
159+
Attributes are defined in FastJsonapi using the `attributes` method. This method is also aliased as `attribute`, which is useful when defining a single attribute.
160+
161+
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:
162+
163+
```ruby
164+
class MovieSerializer
165+
include FastJsonapi::ObjectSerializer
166+
167+
attribute :name
168+
end
169+
```
170+
171+
Custom attributes that must be serialized but do not exist on the model can be declared using Ruby block syntax:
172+
173+
```ruby
174+
class MovieSerializer
175+
include FastJsonapi::ObjectSerializer
176+
177+
attributes :name, :year
178+
179+
attribute :name_with_year do |object|
180+
"#{object.name} (#{object.year})"
181+
end
182+
end
183+
```
184+
185+
The block syntax can also be used to override the property on the object:
186+
187+
```ruby
188+
class MovieSerializer
189+
include FastJsonapi::ObjectSerializer
190+
191+
attribute :name do |object|
192+
"#{object.name} Part 2"
193+
end
194+
end
195+
```
196+
158197
### Compound Document
159198

160199
Support for top-level included member through ` options[:include] `.

lib/fast_jsonapi/object_serializer.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,16 +140,18 @@ def cache_options(cache_options)
140140
self.cache_length = cache_options[:cache_length] || 5.minutes
141141
end
142142

143-
def attributes(*attributes_list)
143+
def attributes(*attributes_list, &block)
144144
attributes_list = attributes_list.first if attributes_list.first.class.is_a?(Array)
145145
self.attributes_to_serialize = {} if self.attributes_to_serialize.nil?
146146
attributes_list.each do |attr_name|
147147
method_name = attr_name
148148
key = run_key_transform(method_name)
149-
attributes_to_serialize[key] = method_name
149+
attributes_to_serialize[key] = block || method_name
150150
end
151151
end
152152

153+
alias_method :attribute, :attributes
154+
153155
def add_relationship(name, relationship)
154156
self.relationships_to_serialize = {} if relationships_to_serialize.nil?
155157
self.cachable_relationships_to_serialize = {} if cachable_relationships_to_serialize.nil?

lib/fast_jsonapi/serialization_core.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ def ids_hash_from_record_and_relationship(record, relationship)
5252
end
5353

5454
def attributes_hash(record)
55-
attributes_to_serialize.each_with_object({}) do |(key, method_name), attr_hash|
56-
attr_hash[key] = record.public_send(method_name)
55+
attributes_to_serialize.each_with_object({}) do |(key, method), attr_hash|
56+
attr_hash[key] = method.is_a?(Proc) ? method.call(record) : record.public_send(method)
5757
end
5858
end
5959

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
require 'spec_helper'
2+
3+
describe FastJsonapi::ObjectSerializer do
4+
include_context 'movie class'
5+
6+
context 'when including attribute blocks' do
7+
it 'returns correct hash when serializable_hash is called' do
8+
serializable_hash = MovieSerializerWithAttributeBlock.new([movie]).serializable_hash
9+
expect(serializable_hash[:data][0][:attributes][:name]).to eq movie.name
10+
expect(serializable_hash[:data][0][:attributes][:title_with_year]).to eq "#{movie.name} (#{movie.release_year})"
11+
end
12+
end
13+
end

spec/shared/contexts/movie_context.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,15 @@ class MovieTypeSerializer
9696
attributes :name
9797
end
9898

99+
class MovieSerializerWithAttributeBlock
100+
include FastJsonapi::ObjectSerializer
101+
set_type :movie
102+
attributes :name, :release_year
103+
attribute :title_with_year do |record|
104+
"#{record.name} (#{record.release_year})"
105+
end
106+
end
107+
99108
class SupplierSerializer
100109
include FastJsonapi::ObjectSerializer
101110
set_type :supplier
@@ -140,6 +149,7 @@ class MovieSerializer
140149
ActorSerializer
141150
MovieType
142151
MovieTypeSerializer
152+
MovieSerializerWithAttributeBlock
143153
AppName::V1::MovieSerializer
144154
MovieStruct
145155
ActorStruct

0 commit comments

Comments
 (0)