jbuilder 2.7.0 → 2.11.5
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 +5 -5
- data/.github/workflows/ruby.yml +108 -0
- data/.gitignore +2 -0
- data/Appraisals +20 -12
- data/CONTRIBUTING.md +4 -6
- data/Gemfile +0 -1
- data/MIT-LICENSE +1 -1
- data/README.md +99 -19
- data/Rakefile +1 -1
- data/gemfiles/rails_5_0.gemfile +1 -4
- data/gemfiles/rails_5_1.gemfile +1 -4
- data/gemfiles/{rails_4_2.gemfile → rails_5_2.gemfile} +1 -4
- data/gemfiles/rails_6_0.gemfile +10 -0
- data/gemfiles/rails_6_1.gemfile +10 -0
- data/gemfiles/rails_head.gemfile +10 -0
- data/jbuilder.gemspec +18 -4
- data/lib/generators/rails/jbuilder_generator.rb +12 -2
- data/lib/generators/rails/scaffold_controller_generator.rb +6 -0
- data/lib/generators/rails/templates/api_controller.rb +4 -4
- data/lib/generators/rails/templates/controller.rb +15 -19
- data/lib/generators/rails/templates/index.json.jbuilder +1 -1
- data/lib/generators/rails/templates/partial.json.jbuilder +15 -1
- data/lib/jbuilder/collection_renderer.rb +109 -0
- data/lib/jbuilder/jbuilder_template.rb +63 -15
- data/lib/jbuilder/railtie.rb +1 -1
- data/lib/jbuilder.rb +65 -23
- data/test/jbuilder_dependency_tracker_test.rb +2 -2
- data/test/jbuilder_generator_test.rb +25 -5
- data/test/jbuilder_template_test.rb +280 -327
- data/test/jbuilder_test.rb +229 -4
- data/test/scaffold_api_controller_generator_test.rb +18 -3
- data/test/scaffold_controller_generator_test.rb +41 -8
- data/test/test_helper.rb +30 -8
- metadata +21 -14
- data/.travis.yml +0 -66
- data/CHANGELOG.md +0 -249
@@ -1,457 +1,410 @@
|
|
1
1
|
require "test_helper"
|
2
|
-
require "mocha/setup"
|
3
|
-
require "active_model"
|
4
|
-
require "action_view"
|
5
2
|
require "action_view/testing/resolvers"
|
6
|
-
require "active_support/cache"
|
7
|
-
require "jbuilder/jbuilder_template"
|
8
|
-
|
9
|
-
BLOG_POST_PARTIAL = <<-JBUILDER
|
10
|
-
json.extract! blog_post, :id, :body
|
11
|
-
json.author do
|
12
|
-
first_name, last_name = blog_post.author_name.split(nil, 2)
|
13
|
-
json.first_name first_name
|
14
|
-
json.last_name last_name
|
15
|
-
end
|
16
|
-
JBUILDER
|
17
3
|
|
18
|
-
|
19
|
-
|
20
|
-
|
4
|
+
class JbuilderTemplateTest < ActiveSupport::TestCase
|
5
|
+
POST_PARTIAL = <<-JBUILDER
|
6
|
+
json.extract! post, :id, :body
|
7
|
+
json.author do
|
8
|
+
first_name, last_name = post.author_name.split(nil, 2)
|
9
|
+
json.first_name first_name
|
10
|
+
json.last_name last_name
|
11
|
+
end
|
12
|
+
JBUILDER
|
21
13
|
|
22
|
-
|
23
|
-
|
24
|
-
JBUILDER
|
14
|
+
COLLECTION_PARTIAL = <<-JBUILDER
|
15
|
+
json.extract! collection, :id, :name
|
16
|
+
JBUILDER
|
25
17
|
|
26
|
-
|
27
|
-
|
28
|
-
|
18
|
+
RACER_PARTIAL = <<-JBUILDER
|
19
|
+
json.extract! racer, :id, :name
|
20
|
+
JBUILDER
|
29
21
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
end
|
22
|
+
PARTIALS = {
|
23
|
+
"_partial.json.jbuilder" => "json.content content",
|
24
|
+
"_post.json.jbuilder" => POST_PARTIAL,
|
25
|
+
"racers/_racer.json.jbuilder" => RACER_PARTIAL,
|
26
|
+
"_collection.json.jbuilder" => COLLECTION_PARTIAL,
|
36
27
|
|
28
|
+
# Ensure we find only Jbuilder partials from within Jbuilder templates.
|
29
|
+
"_post.html.erb" => "Hello world!"
|
30
|
+
}
|
37
31
|
|
38
|
-
|
39
|
-
|
40
|
-
blog_authors = [ "David Heinemeier Hansson", "Pavel Pravosud" ].cycle
|
41
|
-
BLOG_POST_COLLECTION = Array.new(10){ |i| BlogPost.new(i+1, "post body #{i+1}", blog_authors.next) }
|
42
|
-
COLLECTION_COLLECTION = Array.new(5){ |i| Collection.new(i+1, "collection #{i+1}") }
|
32
|
+
AUTHORS = [ "David Heinemeier Hansson", "Pavel Pravosud" ].cycle
|
33
|
+
POSTS = (1..10).collect { |i| Post.new(i, "Post ##{i}", AUTHORS.next) }
|
43
34
|
|
44
|
-
|
35
|
+
setup { Rails.cache.clear }
|
45
36
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
"_collection.json.jbuilder" => COLLECTION_PARTIAL
|
51
|
-
}
|
37
|
+
test "basic template" do
|
38
|
+
result = render('json.content "hello"')
|
39
|
+
assert_equal "hello", result["content"]
|
40
|
+
end
|
52
41
|
|
53
|
-
|
54
|
-
|
55
|
-
|
42
|
+
test "partial by name with top-level locals" do
|
43
|
+
result = render('json.partial! "partial", content: "hello"')
|
44
|
+
assert_equal "hello", result["content"]
|
56
45
|
end
|
57
|
-
end
|
58
46
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
Rails.cache.clear
|
47
|
+
test "partial by name with nested locals" do
|
48
|
+
result = render('json.partial! "partial", locals: { content: "hello" }')
|
49
|
+
assert_equal "hello", result["content"]
|
63
50
|
end
|
64
51
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
partials["test.json.jbuilder"] = source
|
69
|
-
resolver = ActionView::FixtureResolver.new(partials)
|
70
|
-
lookup_context.view_paths = [resolver]
|
71
|
-
template = ActionView::Template.new(source, "test", JbuilderHandler, virtual_path: "test")
|
72
|
-
json = template.render(self, {}).strip
|
73
|
-
MultiJson.load(json)
|
52
|
+
test "partial by options containing nested locals" do
|
53
|
+
result = render('json.partial! partial: "partial", locals: { content: "hello" }')
|
54
|
+
assert_equal "hello", result["content"]
|
74
55
|
end
|
75
56
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
undef_method name.to_sym if method_defined?(name.to_sym)
|
80
|
-
end
|
81
|
-
end
|
57
|
+
test "partial by options containing top-level locals" do
|
58
|
+
result = render('json.partial! partial: "partial", content: "hello"')
|
59
|
+
assert_equal "hello", result["content"]
|
82
60
|
end
|
83
61
|
|
84
|
-
|
85
|
-
result =
|
62
|
+
test "partial for Active Model" do
|
63
|
+
result = render('json.partial! @racer', racer: Racer.new(123, "Chris Harris"))
|
64
|
+
assert_equal 123, result["id"]
|
65
|
+
assert_equal "Chris Harris", result["name"]
|
66
|
+
end
|
86
67
|
|
87
|
-
|
88
|
-
|
89
|
-
assert_equal
|
68
|
+
test "partial collection by name with symbol local" do
|
69
|
+
result = render('json.partial! "post", collection: @posts, as: :post', posts: POSTS)
|
70
|
+
assert_equal 10, result.count
|
71
|
+
assert_equal "Post #5", result[4]["body"]
|
90
72
|
assert_equal "Heinemeier Hansson", result[2]["author"]["last_name"]
|
91
|
-
assert_equal "Pavel",
|
73
|
+
assert_equal "Pavel", result[5]["author"]["first_name"]
|
92
74
|
end
|
93
75
|
|
94
|
-
test "
|
95
|
-
result =
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
assert_equal "
|
76
|
+
test "partial collection by name with string local" do
|
77
|
+
result = render('json.partial! "post", collection: @posts, as: "post"', posts: POSTS)
|
78
|
+
assert_equal 10, result.count
|
79
|
+
assert_equal "Post #5", result[4]["body"]
|
80
|
+
assert_equal "Heinemeier Hansson", result[2]["author"]["last_name"]
|
81
|
+
assert_equal "Pavel", result[5]["author"]["first_name"]
|
100
82
|
end
|
101
83
|
|
102
|
-
test "
|
103
|
-
result =
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
assert_equal ["camelStyle"], result.keys
|
84
|
+
test "partial collection by options" do
|
85
|
+
result = render('json.partial! partial: "post", collection: @posts, as: :post', posts: POSTS)
|
86
|
+
assert_equal 10, result.count
|
87
|
+
assert_equal "Post #5", result[4]["body"]
|
88
|
+
assert_equal "Heinemeier Hansson", result[2]["author"]["last_name"]
|
89
|
+
assert_equal "Pavel", result[5]["author"]["first_name"]
|
109
90
|
end
|
110
91
|
|
111
|
-
test "
|
112
|
-
|
113
|
-
|
114
|
-
json.level1 "one"
|
115
|
-
json.level2 do
|
116
|
-
json.value "two"
|
117
|
-
end
|
118
|
-
JBUILDER
|
92
|
+
test "nil partial collection by name" do
|
93
|
+
assert_equal [], render('json.partial! "post", collection: @posts, as: :post', posts: nil)
|
94
|
+
end
|
119
95
|
|
120
|
-
|
121
|
-
assert_equal "
|
96
|
+
test "nil partial collection by options" do
|
97
|
+
assert_equal [], render('json.partial! partial: "post", collection: @posts, as: :post', posts: nil)
|
122
98
|
end
|
123
99
|
|
124
|
-
test "
|
125
|
-
result =
|
126
|
-
|
127
|
-
|
100
|
+
test "array of partials" do
|
101
|
+
result = render('json.array! @posts, partial: "post", as: :post', posts: POSTS)
|
102
|
+
assert_equal 10, result.count
|
103
|
+
assert_equal "Post #5", result[4]["body"]
|
104
|
+
assert_equal "Heinemeier Hansson", result[2]["author"]["last_name"]
|
105
|
+
assert_equal "Pavel", result[5]["author"]["first_name"]
|
106
|
+
end
|
128
107
|
|
129
|
-
|
108
|
+
test "empty array of partials from nil collection" do
|
109
|
+
assert_equal [], render('json.array! @posts, partial: "post", as: :post', posts: nil)
|
130
110
|
end
|
131
111
|
|
132
|
-
test "
|
133
|
-
result =
|
134
|
-
|
135
|
-
|
112
|
+
test "array of partials under key" do
|
113
|
+
result = render('json.posts @posts, partial: "post", as: :post', posts: POSTS)
|
114
|
+
assert_equal 10, result["posts"].count
|
115
|
+
assert_equal "Post #5", result["posts"][4]["body"]
|
116
|
+
assert_equal "Heinemeier Hansson", result["posts"][2]["author"]["last_name"]
|
117
|
+
assert_equal "Pavel", result["posts"][5]["author"]["first_name"]
|
118
|
+
end
|
136
119
|
|
137
|
-
|
120
|
+
test "empty array of partials under key from nil collection" do
|
121
|
+
result = render('json.posts @posts, partial: "post", as: :post', posts: nil)
|
122
|
+
assert_equal [], result["posts"]
|
138
123
|
end
|
139
124
|
|
140
|
-
test "
|
141
|
-
|
142
|
-
json.
|
125
|
+
test "object fragment caching" do
|
126
|
+
render(<<-JBUILDER)
|
127
|
+
json.cache! "cache-key" do
|
128
|
+
json.name "Hit"
|
129
|
+
end
|
143
130
|
JBUILDER
|
144
131
|
|
145
|
-
|
132
|
+
hit = render('json.cache! "cache-key" do; end')
|
133
|
+
assert_equal "Hit", hit["name"]
|
146
134
|
end
|
147
135
|
|
148
|
-
test "
|
149
|
-
|
150
|
-
json.
|
136
|
+
test "conditional object fragment caching" do
|
137
|
+
render(<<-JBUILDER)
|
138
|
+
json.cache_if! true, "cache-key" do
|
139
|
+
json.a "Hit"
|
140
|
+
end
|
141
|
+
|
142
|
+
json.cache_if! false, "cache-key" do
|
143
|
+
json.b "Hit"
|
144
|
+
end
|
151
145
|
JBUILDER
|
152
146
|
|
153
|
-
|
154
|
-
|
147
|
+
result = render(<<-JBUILDER)
|
148
|
+
json.cache_if! true, "cache-key" do
|
149
|
+
json.a "Miss"
|
150
|
+
end
|
155
151
|
|
156
|
-
|
157
|
-
|
158
|
-
|
152
|
+
json.cache_if! false, "cache-key" do
|
153
|
+
json.b "Miss"
|
154
|
+
end
|
159
155
|
JBUILDER
|
160
156
|
|
161
|
-
|
157
|
+
assert_equal "Hit", result["a"]
|
158
|
+
assert_equal "Miss", result["b"]
|
162
159
|
end
|
163
160
|
|
164
|
-
test "
|
165
|
-
|
166
|
-
|
161
|
+
test "object fragment caching with expiry" do
|
162
|
+
travel_to Time.iso8601("2018-05-12T11:29:00-04:00")
|
163
|
+
|
164
|
+
render <<-JBUILDER
|
165
|
+
json.cache! "cache-key", expires_in: 1.minute do
|
166
|
+
json.name "Hit"
|
167
|
+
end
|
167
168
|
JBUILDER
|
168
169
|
|
169
|
-
|
170
|
-
end
|
170
|
+
travel 30.seconds
|
171
171
|
|
172
|
-
|
173
|
-
|
174
|
-
|
172
|
+
result = render(<<-JBUILDER)
|
173
|
+
json.cache! "cache-key", expires_in: 1.minute do
|
174
|
+
json.name "Miss"
|
175
|
+
end
|
175
176
|
JBUILDER
|
176
177
|
|
177
|
-
assert_equal
|
178
|
-
|
178
|
+
assert_equal "Hit", result["name"]
|
179
|
+
|
180
|
+
travel 31.seconds
|
179
181
|
|
180
|
-
|
181
|
-
|
182
|
-
|
182
|
+
result = render(<<-JBUILDER)
|
183
|
+
json.cache! "cache-key", expires_in: 1.minute do
|
184
|
+
json.name "Miss"
|
185
|
+
end
|
183
186
|
JBUILDER
|
184
187
|
|
185
|
-
|
188
|
+
assert_equal "Miss", result["name"]
|
186
189
|
end
|
187
190
|
|
188
|
-
test "
|
189
|
-
|
190
|
-
json.
|
191
|
+
test "object root caching" do
|
192
|
+
render <<-JBUILDER
|
193
|
+
json.cache_root! "cache-key" do
|
194
|
+
json.name "Hit"
|
195
|
+
end
|
191
196
|
JBUILDER
|
192
197
|
|
193
|
-
assert_equal
|
194
|
-
end
|
198
|
+
assert_equal JSON.dump(name: "Hit"), Rails.cache.read("jbuilder/root/cache-key")
|
195
199
|
|
196
|
-
|
197
|
-
|
198
|
-
|
200
|
+
result = render(<<-JBUILDER)
|
201
|
+
json.cache_root! "cache-key" do
|
202
|
+
json.name "Miss"
|
203
|
+
end
|
199
204
|
JBUILDER
|
200
205
|
|
201
|
-
|
206
|
+
assert_equal "Hit", result["name"]
|
202
207
|
end
|
203
208
|
|
204
|
-
test "
|
205
|
-
|
206
|
-
json.
|
209
|
+
test "array fragment caching" do
|
210
|
+
render <<-JBUILDER
|
211
|
+
json.cache! "cache-key" do
|
212
|
+
json.array! %w[ a b c ]
|
213
|
+
end
|
207
214
|
JBUILDER
|
208
215
|
|
209
|
-
assert_equal [],
|
216
|
+
assert_equal %w[ a b c ], render('json.cache! "cache-key" do; end')
|
210
217
|
end
|
211
218
|
|
212
|
-
test "
|
213
|
-
|
214
|
-
json.
|
219
|
+
test "array root caching" do
|
220
|
+
render <<-JBUILDER
|
221
|
+
json.cache_root! "cache-key" do
|
222
|
+
json.array! %w[ a b c ]
|
223
|
+
end
|
215
224
|
JBUILDER
|
216
225
|
|
217
|
-
|
218
|
-
end
|
226
|
+
assert_equal JSON.dump(%w[ a b c ]), Rails.cache.read("jbuilder/root/cache-key")
|
219
227
|
|
220
|
-
|
221
|
-
|
222
|
-
|
228
|
+
assert_equal %w[ a b c ], render(<<-JBUILDER)
|
229
|
+
json.cache_root! "cache-key" do
|
230
|
+
json.array! %w[ d e f ]
|
231
|
+
end
|
223
232
|
JBUILDER
|
224
|
-
|
225
|
-
assert_equal [], result["posts"]
|
226
233
|
end
|
227
234
|
|
228
|
-
test "cache
|
229
|
-
|
235
|
+
test "failing to cache root after JSON structures have been defined" do
|
236
|
+
assert_raises ActionView::Template::Error, "cache_root! can't be used after JSON structures have been defined" do
|
237
|
+
render <<-JBUILDER
|
238
|
+
json.name "Kaboom"
|
239
|
+
json.cache_root! "cache-key" do
|
240
|
+
json.name "Miss"
|
241
|
+
end
|
242
|
+
JBUILDER
|
243
|
+
end
|
244
|
+
end
|
230
245
|
|
231
|
-
|
232
|
-
|
233
|
-
end
|
234
|
-
JBUILDER
|
246
|
+
test "empty fragment caching" do
|
247
|
+
render 'json.cache! "nothing" do; end'
|
235
248
|
|
236
249
|
result = nil
|
237
250
|
|
238
251
|
assert_nothing_raised do
|
239
|
-
result =
|
252
|
+
result = render(<<-JBUILDER)
|
240
253
|
json.foo "bar"
|
241
|
-
json.cache! "nothing" do
|
242
|
-
end
|
254
|
+
json.cache! "nothing" do; end
|
243
255
|
JBUILDER
|
244
256
|
end
|
245
257
|
|
246
258
|
assert_equal "bar", result["foo"]
|
247
259
|
end
|
248
260
|
|
249
|
-
test "
|
250
|
-
|
261
|
+
test "cache instrumentation" do
|
262
|
+
payloads = {}
|
251
263
|
|
252
|
-
|
253
|
-
|
254
|
-
json.name "Cache"
|
255
|
-
end
|
256
|
-
JBUILDER
|
264
|
+
ActiveSupport::Notifications.subscribe("read_fragment.action_controller") { |*args| payloads[:read] = args.last }
|
265
|
+
ActiveSupport::Notifications.subscribe("write_fragment.action_controller") { |*args| payloads[:write] = args.last }
|
257
266
|
|
258
|
-
|
259
|
-
json.cache! "
|
260
|
-
json.name "
|
267
|
+
render <<-JBUILDER
|
268
|
+
json.cache! "cache-key" do
|
269
|
+
json.name "Cache"
|
261
270
|
end
|
262
271
|
JBUILDER
|
263
272
|
|
264
|
-
assert_equal "
|
273
|
+
assert_equal "jbuilder/cache-key", payloads[:read][:key]
|
274
|
+
assert_equal "jbuilder/cache-key", payloads[:write][:key]
|
265
275
|
end
|
266
276
|
|
267
|
-
test "
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
json.cache_if! true, "cachekey" do
|
272
|
-
json.test1 "Cache"
|
273
|
-
end
|
274
|
-
json.cache_if! false, "cachekey" do
|
275
|
-
json.test2 "Cache"
|
276
|
-
end
|
277
|
-
JBUILDER
|
278
|
-
|
279
|
-
result = jbuild(<<-JBUILDER)
|
280
|
-
json.cache_if! true, "cachekey" do
|
281
|
-
json.test1 "Miss"
|
282
|
-
end
|
283
|
-
json.cache_if! false, "cachekey" do
|
284
|
-
json.test2 "Miss"
|
285
|
-
end
|
277
|
+
test "camelized keys" do
|
278
|
+
result = render(<<-JBUILDER)
|
279
|
+
json.key_format! camelize: [:lower]
|
280
|
+
json.first_name "David"
|
286
281
|
JBUILDER
|
287
282
|
|
288
|
-
assert_equal "
|
289
|
-
assert_equal "Miss", result["test2"]
|
283
|
+
assert_equal "David", result["firstName"]
|
290
284
|
end
|
291
285
|
|
292
|
-
|
293
|
-
|
286
|
+
if JbuilderTemplate::CollectionRenderer.supported?
|
287
|
+
test "returns an empty array for an empty collection" do
|
288
|
+
result = render('json.array! @posts, partial: "post", as: :post, cached: true', posts: [])
|
294
289
|
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
end
|
299
|
-
JBUILDER
|
300
|
-
|
301
|
-
result = jbuild(<<-JBUILDER)
|
302
|
-
json.cache! "cachekey" do
|
303
|
-
json.array! %w[1 2 3]
|
304
|
-
end
|
305
|
-
JBUILDER
|
306
|
-
|
307
|
-
assert_equal %w[a b c], result
|
308
|
-
end
|
309
|
-
|
310
|
-
test "fragment caching works with current cache digests" do
|
311
|
-
undef_context_methods :fragment_name_with_digest
|
290
|
+
# Do not use #assert_empty as it is important to ensure that the type of the JSON result is an array.
|
291
|
+
assert_equal [], result
|
292
|
+
end
|
312
293
|
|
313
|
-
|
314
|
-
|
294
|
+
test "works with an enumerable object" do
|
295
|
+
enumerable_class = Class.new do
|
296
|
+
include Enumerable
|
297
|
+
alias length count # Rails 6.1 requires this.
|
315
298
|
|
316
|
-
|
317
|
-
|
318
|
-
|
299
|
+
def each(&block)
|
300
|
+
[].each(&block)
|
301
|
+
end
|
319
302
|
end
|
320
|
-
JBUILDER
|
321
|
-
end
|
322
303
|
|
323
|
-
|
324
|
-
undef_context_methods :fragment_name_with_digest, :cache_fragment_name
|
304
|
+
result = render('json.array! @posts, partial: "post", as: :post, cached: true', posts: enumerable_class.new)
|
325
305
|
|
326
|
-
|
306
|
+
# Do not use #assert_empty as it is important to ensure that the type of the JSON result is an array.
|
307
|
+
assert_equal [], result
|
308
|
+
end
|
327
309
|
|
328
|
-
|
329
|
-
json.
|
330
|
-
json.name "Cache"
|
331
|
-
end
|
332
|
-
JBUILDER
|
333
|
-
end
|
310
|
+
test "supports the cached: true option" do
|
311
|
+
result = render('json.array! @posts, partial: "post", as: :post, cached: true', posts: POSTS)
|
334
312
|
|
335
|
-
|
336
|
-
|
313
|
+
assert_equal 10, result.count
|
314
|
+
assert_equal "Post #5", result[4]["body"]
|
315
|
+
assert_equal "Heinemeier Hansson", result[2]["author"]["last_name"]
|
316
|
+
assert_equal "Pavel", result[5]["author"]["first_name"]
|
337
317
|
|
338
|
-
|
339
|
-
|
340
|
-
|
318
|
+
expected = {
|
319
|
+
"id" => 1,
|
320
|
+
"body" => "Post #1",
|
321
|
+
"author" => {
|
322
|
+
"first_name" => "David",
|
323
|
+
"last_name" => "Heinemeier Hansson"
|
324
|
+
}
|
325
|
+
}
|
341
326
|
|
342
|
-
|
343
|
-
json.cache! "cachekey" do
|
344
|
-
json.name "Cache"
|
345
|
-
end
|
346
|
-
JBUILDER
|
327
|
+
assert_equal expected, Rails.cache.read("post-1")
|
347
328
|
|
348
|
-
|
349
|
-
assert_equal "jbuilder/cachekey", payloads[:write_fragment][:key]
|
350
|
-
end
|
329
|
+
result = render('json.array! @posts, partial: "post", as: :post, cached: true', posts: POSTS)
|
351
330
|
|
352
|
-
|
353
|
-
|
331
|
+
assert_equal 10, result.count
|
332
|
+
assert_equal "Post #5", result[4]["body"]
|
333
|
+
assert_equal "Heinemeier Hansson", result[2]["author"]["last_name"]
|
334
|
+
assert_equal "Pavel", result[5]["author"]["first_name"]
|
335
|
+
end
|
354
336
|
|
355
|
-
|
356
|
-
|
337
|
+
test "supports the cached: ->() {} option" do
|
338
|
+
result = render('json.array! @posts, partial: "post", as: :post, cached: ->(post) { [post, "foo"] }', posts: POSTS)
|
357
339
|
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
JBUILDER
|
363
|
-
end
|
340
|
+
assert_equal 10, result.count
|
341
|
+
assert_equal "Post #5", result[4]["body"]
|
342
|
+
assert_equal "Heinemeier Hansson", result[2]["author"]["last_name"]
|
343
|
+
assert_equal "Pavel", result[5]["author"]["first_name"]
|
364
344
|
|
365
|
-
|
366
|
-
|
345
|
+
expected = {
|
346
|
+
"id" => 1,
|
347
|
+
"body" => "Post #1",
|
348
|
+
"author" => {
|
349
|
+
"first_name" => "David",
|
350
|
+
"last_name" => "Heinemeier Hansson"
|
351
|
+
}
|
352
|
+
}
|
367
353
|
|
368
|
-
|
354
|
+
assert_equal expected, Rails.cache.read("post-1/foo")
|
369
355
|
|
370
|
-
|
371
|
-
json.cache! "cachekey", expires_in: 1.minute do
|
372
|
-
json.name "Cache"
|
373
|
-
end
|
374
|
-
JBUILDER
|
375
|
-
end
|
356
|
+
result = render('json.array! @posts, partial: "post", as: :post, cached: ->(post) { [post, "foo"] }', posts: POSTS)
|
376
357
|
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
json.name "Miss"
|
383
|
-
end
|
384
|
-
JBUILDER
|
358
|
+
assert_equal 10, result.count
|
359
|
+
assert_equal "Post #5", result[4]["body"]
|
360
|
+
assert_equal "Heinemeier Hansson", result[2]["author"]["last_name"]
|
361
|
+
assert_equal "Pavel", result[5]["author"]["first_name"]
|
362
|
+
end
|
385
363
|
|
386
|
-
|
387
|
-
|
388
|
-
json.
|
364
|
+
test "raises an error on a render call with the :layout option" do
|
365
|
+
error = assert_raises NotImplementedError do
|
366
|
+
render('json.array! @posts, partial: "post", as: :post, layout: "layout"', posts: POSTS)
|
389
367
|
end
|
390
|
-
JBUILDER
|
391
368
|
|
392
|
-
|
393
|
-
end
|
394
|
-
|
395
|
-
test "failing to cache root after attributes have been defined" do
|
396
|
-
assert_raises ActionView::Template::Error, "cache_root! can't be used after JSON structures have been defined" do
|
397
|
-
jbuild <<-JBUILDER
|
398
|
-
json.name "Kaboom"
|
399
|
-
json.cache_root! "cachekey" do
|
400
|
-
json.name "Miss"
|
401
|
-
end
|
402
|
-
JBUILDER
|
369
|
+
assert_equal "The `:layout' option is not supported in collection rendering.", error.message
|
403
370
|
end
|
404
|
-
end
|
405
|
-
|
406
|
-
test "does not perform caching when controller.perform_caching is false" do
|
407
|
-
controller.perform_caching = false
|
408
371
|
|
409
|
-
|
410
|
-
|
411
|
-
json.
|
372
|
+
test "raises an error on a render call with the :spacer_template option" do
|
373
|
+
error = assert_raises NotImplementedError do
|
374
|
+
render('json.array! @posts, partial: "post", as: :post, spacer_template: "template"', posts: POSTS)
|
412
375
|
end
|
413
|
-
JBUILDER
|
414
|
-
|
415
|
-
assert_equal Rails.cache.inspect[/entries=(\d+)/, 1], "0"
|
416
|
-
end
|
417
|
-
|
418
|
-
test "invokes templates via params via set!" do
|
419
|
-
@post = BLOG_POST_COLLECTION.first
|
420
376
|
|
421
|
-
|
422
|
-
|
423
|
-
JBUILDER
|
424
|
-
|
425
|
-
assert_equal 1, result["post"]["id"]
|
426
|
-
assert_equal "post body 1", result["post"]["body"]
|
427
|
-
assert_equal "David", result["post"]["author"]["first_name"]
|
377
|
+
assert_equal "The `:spacer_template' option is not supported in collection rendering.", error.message
|
378
|
+
end
|
428
379
|
end
|
429
380
|
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
json.partial! @racer
|
435
|
-
JBUILDER
|
381
|
+
private
|
382
|
+
def render(*args)
|
383
|
+
JSON.load render_without_parsing(*args)
|
384
|
+
end
|
436
385
|
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
386
|
+
def render_without_parsing(source, assigns = {})
|
387
|
+
view = build_view(fixtures: PARTIALS.merge("source.json.jbuilder" => source), assigns: assigns)
|
388
|
+
view.render(template: "source")
|
389
|
+
end
|
441
390
|
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
}
|
391
|
+
def build_view(options = {})
|
392
|
+
resolver = ActionView::FixtureResolver.new(options.fetch(:fixtures))
|
393
|
+
lookup_context = ActionView::LookupContext.new([ resolver ], {}, [""])
|
394
|
+
controller = ActionView::TestCase::TestController.new
|
447
395
|
|
448
|
-
|
396
|
+
# TODO: Use with_empty_template_cache unconditionally after dropping support for Rails <6.0.
|
397
|
+
view = if ActionView::Base.respond_to?(:with_empty_template_cache)
|
398
|
+
ActionView::Base.with_empty_template_cache.new(lookup_context, options.fetch(:assigns, {}), controller)
|
399
|
+
else
|
400
|
+
ActionView::Base.new(lookup_context, options.fetch(:assigns, {}), controller)
|
401
|
+
end
|
449
402
|
|
450
|
-
|
451
|
-
|
452
|
-
|
403
|
+
def view.view_cache_dependencies; []; end
|
404
|
+
def view.combined_fragment_cache_key(key) [ key ] end
|
405
|
+
def view.cache_fragment_name(key, *) key end
|
406
|
+
def view.fragment_name_with_digest(key) key end
|
453
407
|
|
454
|
-
|
455
|
-
|
456
|
-
end
|
408
|
+
view
|
409
|
+
end
|
457
410
|
end
|