jbuilder 2.13.0 → 2.14.0

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.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'jbuilder/jbuilder'
2
4
  require 'jbuilder/collection_renderer'
3
5
  require 'action_dispatch/http/mime_type'
@@ -10,10 +12,11 @@ class JbuilderTemplate < Jbuilder
10
12
 
11
13
  self.template_lookup_options = { handlers: [:jbuilder] }
12
14
 
13
- def initialize(context, *args)
15
+ def initialize(context, options = nil)
14
16
  @context = context
15
17
  @cached_root = nil
16
- super(*args)
18
+
19
+ options.nil? ? super() : super(**options)
17
20
  end
18
21
 
19
22
  # Generates JSON using the template specified with the `:partial` option. For example, the code below will render
@@ -52,7 +55,9 @@ class JbuilderTemplate < Jbuilder
52
55
  if args.one? && _is_active_model?(args.first)
53
56
  _render_active_model_partial args.first
54
57
  else
55
- _render_explicit_partial(*args)
58
+ options = args.extract_options!.dup
59
+ options[:partial] = args.first if args.present?
60
+ _render_partial_with_options options
56
61
  end
57
62
  end
58
63
 
@@ -118,7 +123,9 @@ class JbuilderTemplate < Jbuilder
118
123
  options = args.first
119
124
 
120
125
  if args.one? && _partial_options?(options)
121
- partial! options.merge(collection: collection)
126
+ options = options.dup
127
+ options[:collection] = collection
128
+ _render_partial_with_options options
122
129
  else
123
130
  super
124
131
  end
@@ -128,7 +135,7 @@ class JbuilderTemplate < Jbuilder
128
135
  options = args.first
129
136
 
130
137
  if args.one? && _partial_options?(options)
131
- _set_inline_partial name, object, options
138
+ _set_inline_partial name, object, options.dup
132
139
  else
133
140
  super
134
141
  end
@@ -136,15 +143,17 @@ class JbuilderTemplate < Jbuilder
136
143
 
137
144
  private
138
145
 
146
+ alias_method :method_missing, :set!
147
+
139
148
  def _render_partial_with_options(options)
140
- options.reverse_merge! locals: options.except(:partial, :as, :collection, :cached)
141
- options.reverse_merge! ::JbuilderTemplate.template_lookup_options
149
+ options[:locals] ||= options.except(:partial, :as, :collection, :cached)
150
+ options[:handlers] ||= ::JbuilderTemplate.template_lookup_options[:handlers]
142
151
  as = options[:as]
143
152
 
144
- if as && options.key?(:collection) && CollectionRenderer.supported?
153
+ if as && options.key?(:collection)
145
154
  collection = options.delete(:collection) || []
146
155
  partial = options.delete(:partial)
147
- options[:locals].merge!(json: self)
156
+ options[:locals][:json] = self
148
157
  collection = EnumerableCompat.new(collection) if collection.respond_to?(:count) && !collection.respond_to?(:size)
149
158
 
150
159
  if options.has_key?(:layout)
@@ -159,24 +168,8 @@ class JbuilderTemplate < Jbuilder
159
168
  results = CollectionRenderer
160
169
  .new(@context.lookup_context, options) { |&block| _scope(&block) }
161
170
  .render_collection_with_partial(collection, partial, @context, nil)
162
-
163
- array! if results.respond_to?(:body) && results.body.nil?
164
- else
165
- array!
166
- end
167
- elsif as && options.key?(:collection) && !CollectionRenderer.supported?
168
- # For Rails <= 5.2:
169
- as = as.to_sym
170
- collection = options.delete(:collection)
171
171
 
172
- if collection.present?
173
- locals = options.delete(:locals)
174
- array! collection do |member|
175
- member_locals = locals.clone
176
- member_locals.merge! collection: collection
177
- member_locals.merge! as => member
178
- _render_partial options.merge(locals: member_locals)
179
- end
172
+ array! if results.respond_to?(:body) && results.body.nil?
180
173
  else
181
174
  array!
182
175
  end
@@ -186,7 +179,7 @@ class JbuilderTemplate < Jbuilder
186
179
  end
187
180
 
188
181
  def _render_partial(options)
189
- options[:locals].merge! json: self
182
+ options[:locals][:json] = self
190
183
  @context.render options
191
184
  end
192
185
 
@@ -242,34 +235,18 @@ class JbuilderTemplate < Jbuilder
242
235
  value = if object.nil?
243
236
  []
244
237
  elsif _is_collection?(object)
245
- _scope{ _render_partial_with_options options.merge(collection: object) }
246
- else
247
- locals = ::Hash[options[:as], object]
248
- _scope{ _render_partial_with_options options.merge(locals: locals) }
249
- end
250
-
251
- set! name, value
252
- end
253
-
254
- def _render_explicit_partial(name_or_options, locals = {})
255
- case name_or_options
256
- when ::Hash
257
- # partial! partial: 'name', foo: 'bar'
258
- options = name_or_options
238
+ _scope do
239
+ options[:collection] = object
240
+ _render_partial_with_options options
241
+ end
259
242
  else
260
- # partial! 'name', locals: {foo: 'bar'}
261
- if locals.one? && (locals.keys.first == :locals)
262
- options = locals.merge(partial: name_or_options)
263
- else
264
- options = { partial: name_or_options, locals: locals }
243
+ _scope do
244
+ options[:locals] = { options[:as] => object }
245
+ _render_partial_with_options options
265
246
  end
266
- # partial! 'name', foo: 'bar'
267
- as = locals.delete(:as)
268
- options[:as] = as if as.present?
269
- options[:collection] = locals[:collection] if locals.key?(:collection)
270
247
  end
271
248
 
272
- _render_partial_with_options options
249
+ _set_value name, value
273
250
  end
274
251
 
275
252
  def _render_active_model_partial(object)
@@ -284,7 +261,7 @@ class JbuilderHandler
284
261
  def self.call(template, source = nil)
285
262
  source ||= template.source
286
263
  # this juggling is required to keep line numbers right in the error
287
- %{__already_defined = defined?(json); json||=JbuilderTemplate.new(self); #{source}
264
+ %{__already_defined = defined?(json); json||=JbuilderTemplate.new(self); #{source};
288
265
  json.target! unless (__already_defined && __already_defined != "method")}
289
266
  end
290
267
  end
@@ -1,32 +1,30 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'jbuilder/jbuilder'
2
- require 'active_support/core_ext/array'
3
4
 
4
5
  class Jbuilder
5
6
  class KeyFormatter
6
- def initialize(*args)
7
- @format = {}
8
- @cache = {}
9
-
10
- options = args.extract_options!
11
- args.each do |name|
12
- @format[name] = []
13
- end
14
- options.each do |name, parameters|
15
- @format[name] = parameters
16
- end
17
- end
18
-
19
- def initialize_copy(original)
7
+ def initialize(*formats, **formats_with_options)
8
+ @mutex = Mutex.new
9
+ @formats = formats
10
+ @formats_with_options = formats_with_options
20
11
  @cache = {}
21
12
  end
22
13
 
23
14
  def format(key)
24
- @cache[key] ||= @format.inject(key.to_s) do |result, args|
25
- func, args = args
26
- if ::Proc === func
27
- func.call result, *args
28
- else
29
- result.send func, *args
15
+ @mutex.synchronize do
16
+ @cache[key] ||= begin
17
+ value = key.is_a?(Symbol) ? key.name : key.to_s
18
+
19
+ @formats.each do |func|
20
+ value = func.is_a?(Proc) ? func.call(value) : value.send(func)
21
+ end
22
+
23
+ @formats_with_options.each do |func, params|
24
+ value = func.is_a?(Proc) ? func.call(value, *params) : value.send(func, *params)
25
+ end
26
+
27
+ value
30
28
  end
31
29
  end
32
30
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'rails'
2
4
  require 'jbuilder/jbuilder_template'
3
5
 
@@ -9,28 +11,24 @@ class Jbuilder
9
11
  require 'jbuilder/jbuilder_dependency_tracker'
10
12
  end
11
13
 
12
- if Rails::VERSION::MAJOR >= 5
13
- module ::ActionController
14
- module ApiRendering
15
- include ActionView::Rendering
16
- end
14
+ module ::ActionController
15
+ module ApiRendering
16
+ include ActionView::Rendering
17
17
  end
18
+ end
18
19
 
19
- ActiveSupport.on_load :action_controller do
20
- if name == 'ActionController::API'
21
- include ActionController::Helpers
22
- include ActionController::ImplicitRender
23
- end
24
- end
20
+ ActiveSupport.on_load :action_controller_api do
21
+ include ActionController::Helpers
22
+ include ActionController::ImplicitRender
23
+ helper_method :combined_fragment_cache_key
24
+ helper_method :view_cache_dependencies
25
25
  end
26
26
  end
27
27
 
28
- if Rails::VERSION::MAJOR >= 4
29
- generators do |app|
30
- Rails::Generators.configure! app.config.generators
31
- Rails::Generators.hidden_namespaces.uniq!
32
- require 'generators/rails/scaffold_controller_generator'
33
- end
28
+ generators do |app|
29
+ Rails::Generators.configure! app.config.generators
30
+ Rails::Generators.hidden_namespaces.uniq!
31
+ require 'generators/rails/scaffold_controller_generator'
34
32
  end
35
33
  end
36
34
  end
@@ -1,3 +1,5 @@
1
- class Jbuilder
2
- VERSION = "2.13.0"
1
+ # frozen_string_literal: true
2
+
3
+ class Jbuilder < BasicObject
4
+ VERSION = "2.14.0"
3
5
  end
data/lib/jbuilder.rb CHANGED
@@ -1,9 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support'
2
4
  require 'jbuilder/jbuilder'
3
5
  require 'jbuilder/blank'
4
6
  require 'jbuilder/key_formatter'
5
7
  require 'jbuilder/errors'
6
- require 'jbuilder/version'
7
8
  require 'json'
8
9
  require 'active_support/core_ext/hash/deep_merge'
9
10
 
@@ -12,14 +13,18 @@ class Jbuilder
12
13
  @@ignore_nil = false
13
14
  @@deep_format_keys = false
14
15
 
15
- def initialize(options = {})
16
+ def initialize(
17
+ key_formatter: @@key_formatter,
18
+ ignore_nil: @@ignore_nil,
19
+ deep_format_keys: @@deep_format_keys,
20
+ &block
21
+ )
16
22
  @attributes = {}
23
+ @key_formatter = key_formatter
24
+ @ignore_nil = ignore_nil
25
+ @deep_format_keys = deep_format_keys
17
26
 
18
- @key_formatter = options.fetch(:key_formatter){ @@key_formatter ? @@key_formatter.clone : nil}
19
- @ignore_nil = options.fetch(:ignore_nil, @@ignore_nil)
20
- @deep_format_keys = options.fetch(:deep_format_keys, @@deep_format_keys)
21
-
22
- yield self if ::Kernel.block_given?
27
+ yield self if block
23
28
  end
24
29
 
25
30
  # Yields a builder and automatically turns the result into a JSON string
@@ -58,20 +63,12 @@ class Jbuilder
58
63
  else
59
64
  # json.author @post.creator, :name, :email_address
60
65
  # { "author": { "name": "David", "email_address": "david@loudthinking.com" } }
61
- _merge_block(key){ extract! value, *args }
66
+ _merge_block(key){ _extract value, args }
62
67
  end
63
68
 
64
69
  _set_value key, result
65
70
  end
66
71
 
67
- def method_missing(*args, &block)
68
- if ::Kernel.block_given?
69
- set!(*args, &block)
70
- else
71
- set!(*args)
72
- end
73
- end
74
-
75
72
  # Specifies formatting to be applied to the key. Passing in a name of a function
76
73
  # will cause that function to be called on the key. So :upcase will upper case
77
74
  # the key. You can also pass in lambdas for more complex transformations.
@@ -100,13 +97,13 @@ class Jbuilder
100
97
  #
101
98
  # { "_first_name": "David" }
102
99
  #
103
- def key_format!(*args)
104
- @key_formatter = KeyFormatter.new(*args)
100
+ def key_format!(...)
101
+ @key_formatter = KeyFormatter.new(...)
105
102
  end
106
103
 
107
104
  # Same as the instance method key_format! except sets the default.
108
- def self.key_format(*args)
109
- @@key_formatter = KeyFormatter.new(*args)
105
+ def self.key_format(...)
106
+ @@key_formatter = KeyFormatter.new(...)
110
107
  end
111
108
 
112
109
  # If you want to skip adding nil values to your JSON hash. This is useful
@@ -215,7 +212,7 @@ class Jbuilder
215
212
  elsif ::Kernel.block_given?
216
213
  _map_collection(collection, &block)
217
214
  elsif attributes.any?
218
- _map_collection(collection) { |element| extract! element, *attributes }
215
+ _map_collection(collection) { |element| _extract element, attributes }
219
216
  else
220
217
  _format_keys(collection.to_a)
221
218
  end
@@ -241,18 +238,14 @@ class Jbuilder
241
238
  #
242
239
  # json.(@person, :name, :age)
243
240
  def extract!(object, *attributes)
244
- if ::Hash === object
245
- _extract_hash_values(object, attributes)
246
- else
247
- _extract_method_values(object, attributes)
248
- end
241
+ _extract object, attributes
249
242
  end
250
243
 
251
244
  def call(object, *attributes, &block)
252
245
  if ::Kernel.block_given?
253
246
  array! object, &block
254
247
  else
255
- extract! object, *attributes
248
+ _extract object, attributes
256
249
  end
257
250
  end
258
251
 
@@ -281,6 +274,16 @@ class Jbuilder
281
274
 
282
275
  private
283
276
 
277
+ alias_method :method_missing, :set!
278
+
279
+ def _extract(object, attributes)
280
+ if ::Hash === object
281
+ _extract_hash_values(object, attributes)
282
+ else
283
+ _extract_method_values(object, attributes)
284
+ end
285
+ end
286
+
284
287
  def _extract_hash_values(object, attributes)
285
288
  attributes.each{ |key| _set_value key, _format_keys(object.fetch(key)) }
286
289
  end
@@ -311,7 +314,13 @@ class Jbuilder
311
314
  end
312
315
 
313
316
  def _key(key)
314
- @key_formatter ? @key_formatter.format(key) : key.to_s
317
+ if @key_formatter
318
+ @key_formatter.format(key)
319
+ elsif key.is_a?(::Symbol)
320
+ key.name
321
+ else
322
+ key.to_s
323
+ end
315
324
  end
316
325
 
317
326
  def _format_keys(hash_or_array)
@@ -350,16 +359,12 @@ class Jbuilder
350
359
  end
351
360
 
352
361
  def _is_collection?(object)
353
- _object_respond_to?(object, :map, :count) && !(::Struct === object)
362
+ object.respond_to?(:map) && object.respond_to?(:count) && !(::Struct === object)
354
363
  end
355
364
 
356
365
  def _blank?(value=@attributes)
357
366
  BLANK == value
358
367
  end
359
-
360
- def _object_respond_to?(object, *methods)
361
- methods.all?{ |m| object.respond_to?(m) }
362
- end
363
368
  end
364
369
 
365
370
  require 'jbuilder/railtie' if defined?(Rails)
@@ -56,15 +56,13 @@ class JbuilderGeneratorTest < Rails::Generators::TestCase
56
56
  end
57
57
  end
58
58
 
59
- if Rails::VERSION::MAJOR >= 6
60
- test 'handles virtual attributes' do
61
- run_generator %w(Message content:rich_text video:attachment photos:attachments)
59
+ test 'handles virtual attributes' do
60
+ run_generator %w(Message content:rich_text video:attachment photos:attachments)
62
61
 
63
- assert_file 'app/views/messages/_message.json.jbuilder' do |content|
64
- assert_match %r{json\.content message\.content\.to_s}, content
65
- assert_match %r{json\.video url_for\(message\.video\)}, content
66
- assert_match %r{json\.photos do\n json\.array!\(message\.photos\) do \|photo\|\n json\.id photo\.id\n json\.url url_for\(photo\)\n end\nend}, content
67
- end
62
+ assert_file 'app/views/messages/_message.json.jbuilder' do |content|
63
+ assert_match %r{json\.content message\.content\.to_s}, content
64
+ assert_match %r{json\.video url_for\(message\.video\)}, content
65
+ assert_match %r{json\.photos do\n json\.array!\(message\.photos\) do \|photo\|\n json\.id photo\.id\n json\.url url_for\(photo\)\n end\nend}, content
68
66
  end
69
67
  end
70
68
  end
@@ -49,6 +49,17 @@ class JbuilderTemplateTest < ActiveSupport::TestCase
49
49
  assert_equal "hello", result["content"]
50
50
  end
51
51
 
52
+ test "partial by name with hash value omission (punning) as last statement [3.1+]" do
53
+ major, minor, _ = RUBY_VERSION.split(".").map(&:to_i)
54
+ return unless (major == 3 && minor >= 1) || major > 3
55
+
56
+ result = render(<<-JBUILDER)
57
+ content = "hello"
58
+ json.partial! "partial", content:
59
+ JBUILDER
60
+ assert_equal "hello", result["content"]
61
+ end
62
+
52
63
  test "partial by options containing nested locals" do
53
64
  result = render('json.partial! partial: "partial", locals: { content: "hello" }')
54
65
  assert_equal "hello", result["content"]
@@ -306,99 +317,97 @@ class JbuilderTemplateTest < ActiveSupport::TestCase
306
317
  assert_equal "David", result["firstName"]
307
318
  end
308
319
 
309
- if JbuilderTemplate::CollectionRenderer.supported?
310
- test "returns an empty array for an empty collection" do
311
- Jbuilder::CollectionRenderer.expects(:new).never
312
- result = render('json.array! @posts, partial: "post", as: :post, cached: true', posts: [])
320
+ test "returns an empty array for an empty collection" do
321
+ Jbuilder::CollectionRenderer.expects(:new).never
322
+ result = render('json.array! @posts, partial: "post", as: :post, cached: true', posts: [])
313
323
 
314
- # Do not use #assert_empty as it is important to ensure that the type of the JSON result is an array.
315
- assert_equal [], result
316
- end
324
+ # Do not use #assert_empty as it is important to ensure that the type of the JSON result is an array.
325
+ assert_equal [], result
326
+ end
317
327
 
318
- test "works with an enumerable object" do
319
- enumerable_class = Class.new do
320
- include Enumerable
328
+ test "works with an enumerable object" do
329
+ enumerable_class = Class.new do
330
+ include Enumerable
321
331
 
322
- def each(&block)
323
- [].each(&block)
324
- end
332
+ def each(&block)
333
+ [].each(&block)
325
334
  end
335
+ end
326
336
 
327
- result = render('json.array! @posts, partial: "post", as: :post, cached: true', posts: enumerable_class.new)
337
+ result = render('json.array! @posts, partial: "post", as: :post, cached: true', posts: enumerable_class.new)
328
338
 
329
- # Do not use #assert_empty as it is important to ensure that the type of the JSON result is an array.
330
- assert_equal [], result
331
- end
339
+ # Do not use #assert_empty as it is important to ensure that the type of the JSON result is an array.
340
+ assert_equal [], result
341
+ end
342
+
343
+ test "supports the cached: true option" do
344
+ result = render('json.array! @posts, partial: "post", as: :post, cached: true', posts: POSTS)
332
345
 
333
- test "supports the cached: true option" do
334
- result = render('json.array! @posts, partial: "post", as: :post, cached: true', posts: POSTS)
335
-
336
- assert_equal 10, result.count
337
- assert_equal "Post #5", result[4]["body"]
338
- assert_equal "Heinemeier Hansson", result[2]["author"]["last_name"]
339
- assert_equal "Pavel", result[5]["author"]["first_name"]
340
-
341
- expected = {
342
- "id" => 1,
343
- "body" => "Post #1",
344
- "author" => {
345
- "first_name" => "David",
346
- "last_name" => "Heinemeier Hansson"
347
- }
346
+ assert_equal 10, result.count
347
+ assert_equal "Post #5", result[4]["body"]
348
+ assert_equal "Heinemeier Hansson", result[2]["author"]["last_name"]
349
+ assert_equal "Pavel", result[5]["author"]["first_name"]
350
+
351
+ expected = {
352
+ "id" => 1,
353
+ "body" => "Post #1",
354
+ "author" => {
355
+ "first_name" => "David",
356
+ "last_name" => "Heinemeier Hansson"
348
357
  }
358
+ }
349
359
 
350
- assert_equal expected, Rails.cache.read("post-1")
360
+ assert_equal expected, Rails.cache.read("post-1")
351
361
 
352
- result = render('json.array! @posts, partial: "post", as: :post, cached: true', posts: POSTS)
362
+ result = render('json.array! @posts, partial: "post", as: :post, cached: true', posts: POSTS)
353
363
 
354
- assert_equal 10, result.count
355
- assert_equal "Post #5", result[4]["body"]
356
- assert_equal "Heinemeier Hansson", result[2]["author"]["last_name"]
357
- assert_equal "Pavel", result[5]["author"]["first_name"]
358
- end
364
+ assert_equal 10, result.count
365
+ assert_equal "Post #5", result[4]["body"]
366
+ assert_equal "Heinemeier Hansson", result[2]["author"]["last_name"]
367
+ assert_equal "Pavel", result[5]["author"]["first_name"]
368
+ end
359
369
 
360
- test "supports the cached: ->() {} option" do
361
- result = render('json.array! @posts, partial: "post", as: :post, cached: ->(post) { [post, "foo"] }', posts: POSTS)
362
-
363
- assert_equal 10, result.count
364
- assert_equal "Post #5", result[4]["body"]
365
- assert_equal "Heinemeier Hansson", result[2]["author"]["last_name"]
366
- assert_equal "Pavel", result[5]["author"]["first_name"]
367
-
368
- expected = {
369
- "id" => 1,
370
- "body" => "Post #1",
371
- "author" => {
372
- "first_name" => "David",
373
- "last_name" => "Heinemeier Hansson"
374
- }
375
- }
370
+ test "supports the cached: ->() {} option" do
371
+ result = render('json.array! @posts, partial: "post", as: :post, cached: ->(post) { [post, "foo"] }', posts: POSTS)
376
372
 
377
- assert_equal expected, Rails.cache.read("post-1/foo")
373
+ assert_equal 10, result.count
374
+ assert_equal "Post #5", result[4]["body"]
375
+ assert_equal "Heinemeier Hansson", result[2]["author"]["last_name"]
376
+ assert_equal "Pavel", result[5]["author"]["first_name"]
378
377
 
379
- result = render('json.array! @posts, partial: "post", as: :post, cached: ->(post) { [post, "foo"] }', posts: POSTS)
378
+ expected = {
379
+ "id" => 1,
380
+ "body" => "Post #1",
381
+ "author" => {
382
+ "first_name" => "David",
383
+ "last_name" => "Heinemeier Hansson"
384
+ }
385
+ }
380
386
 
381
- assert_equal 10, result.count
382
- assert_equal "Post #5", result[4]["body"]
383
- assert_equal "Heinemeier Hansson", result[2]["author"]["last_name"]
384
- assert_equal "Pavel", result[5]["author"]["first_name"]
385
- end
387
+ assert_equal expected, Rails.cache.read("post-1/foo")
386
388
 
387
- test "raises an error on a render call with the :layout option" do
388
- error = assert_raises NotImplementedError do
389
- render('json.array! @posts, partial: "post", as: :post, layout: "layout"', posts: POSTS)
390
- end
389
+ result = render('json.array! @posts, partial: "post", as: :post, cached: ->(post) { [post, "foo"] }', posts: POSTS)
391
390
 
392
- assert_equal "The `:layout' option is not supported in collection rendering.", error.message
391
+ assert_equal 10, result.count
392
+ assert_equal "Post #5", result[4]["body"]
393
+ assert_equal "Heinemeier Hansson", result[2]["author"]["last_name"]
394
+ assert_equal "Pavel", result[5]["author"]["first_name"]
395
+ end
396
+
397
+ test "raises an error on a render call with the :layout option" do
398
+ error = assert_raises NotImplementedError do
399
+ render('json.array! @posts, partial: "post", as: :post, layout: "layout"', posts: POSTS)
393
400
  end
394
401
 
395
- test "raises an error on a render call with the :spacer_template option" do
396
- error = assert_raises NotImplementedError do
397
- render('json.array! @posts, partial: "post", as: :post, spacer_template: "template"', posts: POSTS)
398
- end
402
+ assert_equal "The `:layout' option is not supported in collection rendering.", error.message
403
+ end
399
404
 
400
- assert_equal "The `:spacer_template' option is not supported in collection rendering.", error.message
405
+ test "raises an error on a render call with the :spacer_template option" do
406
+ error = assert_raises NotImplementedError do
407
+ render('json.array! @posts, partial: "post", as: :post, spacer_template: "template"', posts: POSTS)
401
408
  end
409
+
410
+ assert_equal "The `:spacer_template' option is not supported in collection rendering.", error.message
402
411
  end
403
412
 
404
413
  private
@@ -416,12 +425,7 @@ class JbuilderTemplateTest < ActiveSupport::TestCase
416
425
  lookup_context = ActionView::LookupContext.new([ resolver ], {}, [""])
417
426
  controller = ActionView::TestCase::TestController.new
418
427
 
419
- # TODO: Use with_empty_template_cache unconditionally after dropping support for Rails <6.0.
420
- view = if ActionView::Base.respond_to?(:with_empty_template_cache)
421
- ActionView::Base.with_empty_template_cache.new(lookup_context, options.fetch(:assigns, {}), controller)
422
- else
423
- ActionView::Base.new(lookup_context, options.fetch(:assigns, {}), controller)
424
- end
428
+ view = ActionView::Base.with_empty_template_cache.new(lookup_context, options.fetch(:assigns, {}), controller)
425
429
 
426
430
  def view.view_cache_dependencies; []; end
427
431
  def view.combined_fragment_cache_key(key) [ key ] end