fast_jsonapi 1.3 → 1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ad201aff3dee102a9760daee3777a225d73bcfcb
4
- data.tar.gz: a6e4f0f7840f27c95f3530b68542eae6422d8975
3
+ metadata.gz: 759626d247d6cc39f75b0080a9c09493e9fcc93b
4
+ data.tar.gz: 57dc5e3a5fd9014d3a7f276f3c9d353bb9f328f4
5
5
  SHA512:
6
- metadata.gz: c9503ec4e6d642f72b2a5ccb34f4b33bc68e6fda067e1a16e43d6f30f0f5b95f7e86626d608ab38fbe277ff778dae908e71252e354a1834121b013219cd77e0c
7
- data.tar.gz: 069b1ac282d7b2a3f559f398c4090f188c72f8120f4bfeff01f7126a57fbc789725ef3f2e6cf1c88c541a99681914c4f32bb5855655b9f65a7c55262c02f449e
6
+ metadata.gz: 390b6f6df1591307f33afd1996d563ead9f04294a6e9670a82263388c9ae408b94d5321bce265c2ed3336f714999496525fd2a3866e8d710c27791bbfd42193b
7
+ data.tar.gz: 69e7198dea45b109c630555328ea8847af80a2ea4938fc743f862f4f8eb1e8513af090ee537c55ac79b202c1724483ea5b9574567f81fe0ef6d83efb55fb8c7d
data/README.md CHANGED
@@ -221,7 +221,7 @@ end
221
221
  ```
222
222
 
223
223
  ### Links Per Object
224
- Links are defined in FastJsonapi using the `link` method. By default, link are read directly from the model property of the same name.In this example, `public_url` is expected to be a property of the object being serialized.
224
+ Links are defined in FastJsonapi using the `link` method. By default, link are read directly from the model property of the same name. In this example, `public_url` is expected to be a property of the object being serialized.
225
225
 
226
226
  You can configure the method to use on the object for example a link with key `self` will get set to the value returned by a method called `url` on the movie object.
227
227
 
@@ -245,6 +245,23 @@ class MovieSerializer
245
245
  end
246
246
  ```
247
247
 
248
+ ### Meta Per Resource
249
+
250
+ 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.
251
+
252
+
253
+ ```ruby
254
+ class MovieSerializer
255
+ include FastJsonapi::ObjectSerializer
256
+
257
+ meta do |movie|
258
+ {
259
+ years_since_release: Date.current.year - movie.year
260
+ }
261
+ end
262
+ end
263
+ ```
264
+
248
265
  ### Compound Document
249
266
 
250
267
  Support for top-level and nested included associations through ` options[:include] `.
@@ -351,15 +368,15 @@ class MovieSerializer
351
368
  include FastJsonapi::ObjectSerializer
352
369
 
353
370
  attributes :name, :year
354
- attribute :release_year, if: Proc.new do |record|
371
+ attribute :release_year, if: Proc.new { |record|
355
372
  # Release year will only be serialized if it's greater than 1990
356
373
  record.release_year > 1990
357
- end
374
+ }
358
375
 
359
- attribute :director, if: Proc.new do |record, params|
376
+ attribute :director, if: Proc.new { |record, params|
360
377
  # The director will be serialized only if the :admin key of params is true
361
378
  params && params[:admin] == true
362
- end
379
+ }
363
380
  end
364
381
 
365
382
  # ...
@@ -409,6 +426,7 @@ serializer.serializable_hash
409
426
  Option | Purpose | Example
410
427
  ------------ | ------------- | -------------
411
428
  set_type | Type name of Object | ```set_type :movie ```
429
+ key | Key of Object | ```belongs_to :owner, key: :user ```
412
430
  set_id | ID of Object | ```set_id :owner_id ```
413
431
  cache_options | Hash to enable caching and set cache length | ```cache_options enabled: true, cache_length: 12.hours, race_condition_ttl: 10.seconds```
414
432
  id_method_name | Set custom method name to get ID of an object | ```has_many :locations, id_method_name: :place_ids ```
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'active_support/core_ext/object'
3
+ require 'active_support/json'
4
4
  require 'active_support/concern'
5
5
  require 'active_support/inflector'
6
6
  require 'fast_jsonapi/attribute'
@@ -65,7 +65,7 @@ module FastJsonapi
65
65
  end
66
66
 
67
67
  def serialized_json
68
- self.class.to_json(serializable_hash)
68
+ ActiveSupport::JSON.encode(serializable_hash)
69
69
  end
70
70
 
71
71
  private
@@ -120,6 +120,7 @@ module FastJsonapi
120
120
  subclass.data_links = data_links
121
121
  subclass.cached = cached
122
122
  subclass.set_type(subclass.reflected_record_type) if subclass.reflected_record_type
123
+ subclass.meta_to_serialize = meta_to_serialize
123
124
  end
124
125
 
125
126
  def reflected_record_type
@@ -194,7 +195,7 @@ module FastJsonapi
194
195
  self.relationships_to_serialize = {} if relationships_to_serialize.nil?
195
196
  self.cachable_relationships_to_serialize = {} if cachable_relationships_to_serialize.nil?
196
197
  self.uncachable_relationships_to_serialize = {} if uncachable_relationships_to_serialize.nil?
197
-
198
+
198
199
  if !relationship.cached
199
200
  self.uncachable_relationships_to_serialize[relationship.name] = relationship
200
201
  else
@@ -218,6 +219,10 @@ module FastJsonapi
218
219
  add_relationship(relationship)
219
220
  end
220
221
 
222
+ def meta(&block)
223
+ self.meta_to_serialize = block
224
+ end
225
+
221
226
  def create_relationship(base_key, relationship_type, options, block)
222
227
  name = base_key.to_sym
223
228
  if relationship_type == :has_many
@@ -232,7 +237,11 @@ module FastJsonapi
232
237
  Relationship.new(
233
238
  key: options[:key] || run_key_transform(base_key),
234
239
  name: name,
235
- id_method_name: options[:id_method_name] || "#{base_serialization_key}#{id_postfix}".to_sym,
240
+ id_method_name: compute_id_method_name(
241
+ options[:id_method_name],
242
+ "#{base_serialization_key}#{id_postfix}".to_sym,
243
+ block
244
+ ),
236
245
  record_type: options[:record_type] || run_key_transform(base_key_sym),
237
246
  object_method_name: options[:object_method_name] || name,
238
247
  object_block: block,
@@ -240,10 +249,19 @@ module FastJsonapi
240
249
  relationship_type: relationship_type,
241
250
  cached: options[:cached],
242
251
  polymorphic: fetch_polymorphic_option(options),
243
- conditional_proc: options[:if]
252
+ conditional_proc: options[:if],
253
+ transform_method: @transform_method
244
254
  )
245
255
  end
246
256
 
257
+ def compute_id_method_name(custom_id_method_name, id_method_name_from_relationship, block)
258
+ if block.present?
259
+ custom_id_method_name || :id
260
+ else
261
+ custom_id_method_name || id_method_name_from_relationship
262
+ end
263
+ end
264
+
247
265
  def compute_serializer_name(serializer_key)
248
266
  return serializer_key unless serializer_key.is_a? Symbol
249
267
  namespace = self.name.gsub(/()?\w+Serializer$/, '')
@@ -275,10 +293,10 @@ module FastJsonapi
275
293
  includes.detect do |include_item|
276
294
  klass = self
277
295
  parse_include_item(include_item).each do |parsed_include|
278
- relationship_to_include = klass.relationships_to_serialize[parsed_include]
296
+ relationships_to_serialize = klass.relationships_to_serialize || {}
297
+ relationship_to_include = relationships_to_serialize[parsed_include]
279
298
  raise ArgumentError, "#{parsed_include} is not specified as a relationship on #{klass.name}" unless relationship_to_include
280
- raise NotImplementedError if relationship_to_include.polymorphic.is_a?(Hash)
281
- klass = relationship_to_include.serializer.to_s.constantize
299
+ klass = relationship_to_include.serializer.to_s.constantize unless relationship_to_include.polymorphic.is_a?(Hash)
282
300
  end
283
301
  end
284
302
  end
@@ -1,6 +1,6 @@
1
1
  module FastJsonapi
2
2
  class Relationship
3
- attr_reader :key, :name, :id_method_name, :record_type, :object_method_name, :object_block, :serializer, :relationship_type, :cached, :polymorphic, :conditional_proc
3
+ attr_reader :key, :name, :id_method_name, :record_type, :object_method_name, :object_block, :serializer, :relationship_type, :cached, :polymorphic, :conditional_proc, :transform_method
4
4
 
5
5
  def initialize(
6
6
  key:,
@@ -13,7 +13,8 @@ module FastJsonapi
13
13
  relationship_type:,
14
14
  cached: false,
15
15
  polymorphic:,
16
- conditional_proc:
16
+ conditional_proc:,
17
+ transform_method:
17
18
  )
18
19
  @key = key
19
20
  @name = name
@@ -26,6 +27,7 @@ module FastJsonapi
26
27
  @cached = cached
27
28
  @polymorphic = polymorphic
28
29
  @conditional_proc = conditional_proc
30
+ @transform_method = transform_method
29
31
  end
30
32
 
31
33
  def serialize(record, serialization_params, output_hash)
@@ -68,7 +70,7 @@ module FastJsonapi
68
70
 
69
71
  def id_hash_from_record(record, record_types)
70
72
  # memoize the record type within the record_types dictionary, then assigning to record_type:
71
- associated_record_type = record_types[record.class] ||= record.class.name.underscore.to_sym
73
+ associated_record_type = record_types[record.class] ||= run_key_transform(record.class.name.demodulize.underscore)
72
74
  id_hash(record.id, associated_record_type)
73
75
  end
74
76
 
@@ -86,14 +88,20 @@ module FastJsonapi
86
88
  end
87
89
 
88
90
  def fetch_id(record, params)
89
- unless object_block.nil?
91
+ if object_block.present?
90
92
  object = object_block.call(record, params)
91
-
92
- return object.map(&:id) if object.respond_to? :map
93
- return object.try(:id)
93
+ return object.map { |item| item.public_send(id_method_name) } if object.respond_to? :map
94
+ return object.try(id_method_name)
94
95
  end
95
-
96
96
  record.public_send(id_method_name)
97
97
  end
98
+
99
+ def run_key_transform(input)
100
+ if self.transform_method.present?
101
+ input.to_s.send(*self.transform_method).to_sym
102
+ else
103
+ input.to_sym
104
+ end
105
+ end
98
106
  end
99
- end
107
+ end
@@ -21,7 +21,8 @@ module FastJsonapi
21
21
  :cache_length,
22
22
  :race_condition_ttl,
23
23
  :cached,
24
- :data_links
24
+ :data_links,
25
+ :meta_to_serialize
25
26
  end
26
27
  end
27
28
 
@@ -57,6 +58,10 @@ module FastJsonapi
57
58
  end
58
59
  end
59
60
 
61
+ def meta_hash(record, params = {})
62
+ meta_to_serialize.call(record, params)
63
+ end
64
+
60
65
  def record_hash(record, fieldset, params = {})
61
66
  if cached
62
67
  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
67
72
  temp_hash[:links] = links_hash(record, params) if data_links.present?
68
73
  temp_hash
69
74
  end
70
- record_hash[:relationships] = record_hash[:relationships].merge(relationships_hash(record, uncachable_relationships_to_serialize, params)) if uncachable_relationships_to_serialize.present?
75
+ record_hash[:relationships] = record_hash[:relationships].merge(relationships_hash(record, uncachable_relationships_to_serialize, fieldset, params)) if uncachable_relationships_to_serialize.present?
76
+ record_hash[:meta] = meta_hash(record, params) if meta_to_serialize.present?
71
77
  record_hash
72
78
  else
73
79
  record_hash = id_hash(id_from_record(record), record_type, true)
74
80
  record_hash[:attributes] = attributes_hash(record, fieldset, params) if attributes_to_serialize.present?
75
81
  record_hash[:relationships] = relationships_hash(record, nil, fieldset, params) if relationships_to_serialize.present?
76
82
  record_hash[:links] = links_hash(record, params) if data_links.present?
83
+ record_hash[:meta] = meta_hash(record, params) if meta_to_serialize.present?
77
84
  record_hash
78
85
  end
79
86
  end
@@ -112,9 +119,10 @@ module FastJsonapi
112
119
  next unless relationships_to_serialize && relationships_to_serialize[item]
113
120
  relationship_item = relationships_to_serialize[item]
114
121
  next unless relationship_item.include_relationship?(record, params)
115
- raise NotImplementedError if relationship_item.polymorphic.is_a?(Hash)
116
- record_type = relationship_item.record_type
117
- serializer = relationship_item.serializer.to_s.constantize
122
+ unless relationship_item.polymorphic.is_a?(Hash)
123
+ record_type = relationship_item.record_type
124
+ serializer = relationship_item.serializer.to_s.constantize
125
+ end
118
126
  relationship_type = relationship_item.relationship_type
119
127
 
120
128
  included_objects = relationship_item.fetch_associated_object(record, params)
@@ -122,12 +130,17 @@ module FastJsonapi
122
130
  included_objects = [included_objects] unless relationship_type == :has_many
123
131
 
124
132
  included_objects.each do |inc_obj|
133
+ if relationship_item.polymorphic.is_a?(Hash)
134
+ record_type = inc_obj.class.name.demodulize.underscore
135
+ serializer = self.compute_serializer_name(inc_obj.class.name.demodulize.to_sym).to_s.constantize
136
+ end
137
+
125
138
  if remaining_items(items)
126
- serializer_records = serializer.get_included_records(inc_obj, remaining_items(items), known_included_objects, fieldsets)
139
+ serializer_records = serializer.get_included_records(inc_obj, remaining_items(items), known_included_objects, fieldsets, params)
127
140
  included_records.concat(serializer_records) unless serializer_records.empty?
128
141
  end
129
142
 
130
- code = "#{record_type}_#{inc_obj.id}"
143
+ code = "#{record_type}_#{serializer.id_from_record(inc_obj)}"
131
144
  next if known_included_objects.key?(code)
132
145
 
133
146
  known_included_objects[code] = inc_obj
@@ -1,3 +1,3 @@
1
1
  module FastJsonapi
2
- VERSION = "1.3"
2
+ VERSION = "1.4"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fast_jsonapi
3
3
  version: !ruby/object:Gem::Version
4
- version: '1.3'
4
+ version: '1.4'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shishir Kakaraddi
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2018-07-17 00:00:00.000000000 Z
13
+ date: 2018-09-20 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport