Skip to content

Commit 85b41c4

Browse files
committed
Adds :lazy_load_data option
If you include a default empty `data` option in your JSON API response, many frontend frameworks will ignore your `related` link that could be used to load relationship records, and will instead treat the relationship as empty. This adds a `lazy_load_data` option which will: * stop the serializer attempting to load the data and; * exclude the `data` key from the final response This allows you to lazy load a JSON API relationship.
1 parent 1efdd33 commit 85b41c4

4 files changed

Lines changed: 43 additions & 22 deletions

File tree

README.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -262,17 +262,15 @@ class MovieSerializer
262262
end
263263
```
264264

265-
This will create a `self` reference for the relationship, and a `related` link for loading the actors relationship later. NB: This will not automatically disable including the data in the relationship, you'll need to do that using the yielded block:
265+
This will create a `self` reference for the relationship, and a `related` link for loading the actors relationship later. NB: This will not automatically disable loading the data in the relationship, you'll need to do that using the `lazy_load_data` option:
266266

267267
```ruby
268-
has_many :actors, links: {
268+
has_many :actors, lazy_load_data: true, links: {
269269
self: :url,
270270
related: -> (object) {
271271
"https://movies.com/#{object.id}/actors"
272272
}
273-
} do |movie|
274-
movie.actors.limit(5)
275-
end
273+
}
276274
```
277275

278276
### Meta Per Resource

lib/fast_jsonapi/object_serializer.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,8 @@ def create_relationship(base_key, relationship_type, options, block)
250250
cached: options[:cached],
251251
polymorphic: fetch_polymorphic_option(options),
252252
conditional_proc: options[:if],
253-
links: options[:links]
253+
links: options[:links],
254+
lazy_load_data: options[:lazy_load_data]
254255
)
255256
end
256257

lib/fast_jsonapi/relationship.rb

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module FastJsonapi
22
class Relationship
3-
attr_reader :key, :name, :id_method_name, :record_type, :object_method_name, :object_block, :serializer, :relationship_type, :cached, :polymorphic, :conditional_proc, :links
3+
attr_reader :key, :name, :id_method_name, :record_type, :object_method_name, :object_block, :serializer, :relationship_type, :cached, :polymorphic, :conditional_proc, :links, :lazy_load_data
44

55
def initialize(
66
key:,
@@ -14,7 +14,8 @@ def initialize(
1414
cached: false,
1515
polymorphic:,
1616
conditional_proc:,
17-
links:
17+
links:,
18+
lazy_load_data: false
1819
)
1920
@key = key
2021
@name = name
@@ -28,14 +29,17 @@ def initialize(
2829
@polymorphic = polymorphic
2930
@conditional_proc = conditional_proc
3031
@links = links || {}
32+
@lazy_load_data = lazy_load_data
3133
end
3234

3335
def serialize(record, serialization_params, output_hash)
3436
if include_relationship?(record, serialization_params)
3537
empty_case = relationship_type == :has_many ? [] : nil
36-
output_hash[key] = {
37-
data: ids_hash_from_record_and_relationship(record, serialization_params) || empty_case
38-
}
38+
39+
output_hash[key] = {}
40+
unless lazy_load_data
41+
output_hash[key][:data] = ids_hash_from_record_and_relationship(record, serialization_params) || empty_case
42+
end
3943
add_links_hash(record, serialization_params, output_hash) if links.present?
4044
end
4145
end

spec/lib/object_serializer_relationship_links_spec.rb

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,23 @@
66
context "params option" do
77
let(:hash) { serializer.serializable_hash }
88

9-
before(:context) do
10-
class MovieSerializer
11-
has_many :actors, links: {
12-
self: :actors_relationship_url,
13-
related: -> (object, params = {}) {
14-
"#{params.has_key?(:secure) ? "https" : "http"}://movies.com/movies/#{object.name.parameterize}/actors/"
15-
}
16-
}
17-
end
18-
end
19-
209
context "generating links for a serializer relationship" do
2110
let(:params) { { } }
2211
let(:options_with_params) { { params: params } }
2312
let(:relationship_url) { "http://movies.com/#{movie.id}/relationships/actors" }
2413
let(:related_url) { "http://movies.com/movies/#{movie.name.parameterize}/actors/" }
2514

15+
before(:context) do
16+
class MovieSerializer
17+
has_many :actors, lazy_load_data: false, links: {
18+
self: :actors_relationship_url,
19+
related: -> (object, params = {}) {
20+
"#{params.has_key?(:secure) ? "https" : "http"}://movies.com/movies/#{object.name.parameterize}/actors/"
21+
}
22+
}
23+
end
24+
end
25+
2626
context "with a single record" do
2727
let(:serializer) { MovieSerializer.new(movie, options_with_params) }
2828
let(:links) { hash[:data][:relationships][:actors][:links] }
@@ -49,5 +49,23 @@ class MovieSerializer
4949
end
5050

5151
end
52+
53+
context "lazy loading relationship data" do
54+
before(:context) do
55+
class LazyLoadingMovieSerializer < MovieSerializer
56+
has_many :actors, lazy_load_data: true, links: {
57+
related: :actors_relationship_url
58+
}
59+
end
60+
end
61+
62+
let(:serializer) { LazyLoadingMovieSerializer.new(movie) }
63+
let(:actor_hash) { hash[:data][:relationships][:actors] }
64+
65+
it "does not include the :data key" do
66+
expect(actor_hash).to be_present
67+
expect(actor_hash).not_to have_key(:data)
68+
end
69+
end
5270
end
5371
end

0 commit comments

Comments
 (0)