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.
- checksums.yaml +4 -4
- data/.devcontainer/devcontainer.json +25 -0
- data/.github/workflows/ruby.yml +14 -7
- data/Appraisals +21 -12
- data/Gemfile +2 -0
- data/README.md +38 -19
- data/Rakefile +2 -0
- data/bin/test +1 -1
- data/gemfiles/rails_7_0.gemfile +1 -0
- data/gemfiles/rails_7_2.gemfile +10 -0
- data/gemfiles/rails_8_0.gemfile +10 -0
- data/jbuilder.gemspec +5 -3
- data/lib/generators/rails/jbuilder_generator.rb +2 -0
- data/lib/generators/rails/scaffold_controller_generator.rb +2 -0
- data/lib/generators/rails/templates/controller.rb +2 -2
- data/lib/jbuilder/blank.rb +2 -0
- data/lib/jbuilder/collection_renderer.rb +19 -77
- data/lib/jbuilder/errors.rb +3 -1
- data/lib/jbuilder/jbuilder.rb +3 -1
- data/lib/jbuilder/jbuilder_dependency_tracker.rb +2 -0
- data/lib/jbuilder/jbuilder_template.rb +29 -52
- data/lib/jbuilder/key_formatter.rb +19 -21
- data/lib/jbuilder/railtie.rb +15 -17
- data/lib/jbuilder/version.rb +4 -2
- data/lib/jbuilder.rb +38 -33
- data/test/jbuilder_generator_test.rb +6 -8
- data/test/jbuilder_template_test.rb +82 -78
- data/test/jbuilder_test.rb +7 -9
- data/test/scaffold_api_controller_generator_test.rb +52 -60
- data/test/scaffold_controller_generator_test.rb +25 -31
- data/test/test_helper.rb +1 -1
- metadata +13 -14
@@ -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,
|
15
|
+
def initialize(context, options = nil)
|
14
16
|
@context = context
|
15
17
|
@cached_root = nil
|
16
|
-
|
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
|
-
|
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
|
-
|
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
|
141
|
-
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)
|
153
|
+
if as && options.key?(:collection)
|
145
154
|
collection = options.delete(:collection) || []
|
146
155
|
partial = options.delete(:partial)
|
147
|
-
options[:locals]
|
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
|
-
|
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]
|
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
|
246
|
-
|
247
|
-
|
248
|
-
|
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
|
-
|
261
|
-
|
262
|
-
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
|
-
|
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(*
|
7
|
-
@
|
8
|
-
@
|
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
|
-
@
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
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
|
data/lib/jbuilder/railtie.rb
CHANGED
@@ -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
|
-
|
13
|
-
module
|
14
|
-
|
15
|
-
include ActionView::Rendering
|
16
|
-
end
|
14
|
+
module ::ActionController
|
15
|
+
module ApiRendering
|
16
|
+
include ActionView::Rendering
|
17
17
|
end
|
18
|
+
end
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
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
|
data/lib/jbuilder/version.rb
CHANGED
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(
|
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
|
-
|
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){
|
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!(
|
104
|
-
@key_formatter = KeyFormatter.new(
|
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(
|
109
|
-
@@key_formatter = KeyFormatter.new(
|
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|
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
60
|
-
|
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
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
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
|
-
|
310
|
-
|
311
|
-
|
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
|
-
|
315
|
-
|
316
|
-
|
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
|
-
|
319
|
-
|
320
|
-
|
328
|
+
test "works with an enumerable object" do
|
329
|
+
enumerable_class = Class.new do
|
330
|
+
include Enumerable
|
321
331
|
|
322
|
-
|
323
|
-
|
324
|
-
end
|
332
|
+
def each(&block)
|
333
|
+
[].each(&block)
|
325
334
|
end
|
335
|
+
end
|
326
336
|
|
327
|
-
|
337
|
+
result = render('json.array! @posts, partial: "post", as: :post, cached: true', posts: enumerable_class.new)
|
328
338
|
|
329
|
-
|
330
|
-
|
331
|
-
|
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
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
"
|
343
|
-
"
|
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
|
-
|
360
|
+
assert_equal expected, Rails.cache.read("post-1")
|
351
361
|
|
352
|
-
|
362
|
+
result = render('json.array! @posts, partial: "post", as: :post, cached: true', posts: POSTS)
|
353
363
|
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
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
|
-
|
361
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
396
|
-
|
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
|
-
|
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
|
-
|
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
|