class JbuilderTemplate

def _cache_fragment_for(key, options, &block)

def _cache_fragment_for(key, options, &block)
  key = _cache_key(key, options)
  _read_fragment_cache(key, options) || _write_fragment_cache(key, options, &block)
end

def _cache_key(key, options)

def _cache_key(key, options)
  name_options = options.slice(:skip_digest, :virtual_path)
  key = _fragment_name_with_digest(key, name_options)
  if @context.respond_to?(:combined_fragment_cache_key)
    key = @context.combined_fragment_cache_key(key)
  else
    key = url_for(key).split('://', 2).last if ::Hash === key
  end
  ::ActiveSupport::Cache.expand_cache_key(key, :jbuilder)
end

def _fragment_name_with_digest(key, options)

def _fragment_name_with_digest(key, options)
  if @context.respond_to?(:cache_fragment_name)
    @context.cache_fragment_name(key, **options)
  else
    key
  end
end

def _is_active_model?(object)

def _is_active_model?(object)
  object.class.respond_to?(:model_name) && object.respond_to?(:to_partial_path)
end

def _partial_options?(options)

def _partial_options?(options)
  ::Hash === options && options.key?(:as) && options.key?(:partial)
end

def _read_fragment_cache(key, options = nil)

def _read_fragment_cache(key, options = nil)
  @context.controller.instrument_fragment_cache :read_fragment, key do
    ::Rails.cache.read(key, options)
  end
end

def _render_active_model_partial(object)

def _render_active_model_partial(object)
  @context.render object, json: self
end

def _render_explicit_partial(name_or_options, locals = {})

def _render_explicit_partial(name_or_options, locals = {})
  case name_or_options
  when ::Hash
    # partial! partial: 'name', foo: 'bar'
    options = name_or_options
  else
    # partial! 'name', locals: {foo: 'bar'}
    if locals.one? && (locals.keys.first == :locals)
      options = locals.merge(partial: name_or_options)
    else
      options = { partial: name_or_options, locals: locals }
    end
    # partial! 'name', foo: 'bar'
    as = locals.delete(:as)
    options[:as] = as if as.present?
    options[:collection] = locals[:collection] if locals.key?(:collection)
  end
  _render_partial_with_options options
end

def _render_partial(options)

def _render_partial(options)
  options[:locals].merge! json: self
  @context.render options
end

def _render_partial_with_options(options)

def _render_partial_with_options(options)
  options.reverse_merge! locals: options.except(:partial, :as, :collection, :cached)
  options.reverse_merge! ::JbuilderTemplate.template_lookup_options
  as = options[:as]
  if as && options.key?(:collection) && CollectionRenderer.supported?
    collection = options.delete(:collection) || []
    partial = options.delete(:partial)
    options[:locals].merge!(json: self)
    collection = EnumerableCompat.new(collection) if collection.respond_to?(:count) && !collection.respond_to?(:size)
    if options.has_key?(:layout)
      ::Kernel.raise ::NotImplementedError, "The `:layout' option is not supported in collection rendering."
    end
    if options.has_key?(:spacer_template)
      ::Kernel.raise ::NotImplementedError, "The `:spacer_template' option is not supported in collection rendering."
    end
    results = CollectionRenderer
      .new(@context.lookup_context, options) { |&block| _scope(&block) }
      .render_collection_with_partial(collection, partial, @context, nil)
    array! if results.respond_to?(:body) && results.body.nil?
  elsif as && options.key?(:collection) && !CollectionRenderer.supported?
    # For Rails <= 5.2:
    as = as.to_sym
    collection = options.delete(:collection)
    locals = options.delete(:locals)
    array! collection do |member|
      member_locals = locals.clone
      member_locals.merge! collection: collection
      member_locals.merge! as => member
      _render_partial options.merge(locals: member_locals)
    end
  else
    _render_partial options
  end
end

def _set_inline_partial(name, object, options)

def _set_inline_partial(name, object, options)
  value = if object.nil?
    []
  elsif _is_collection?(object)
    _scope{ _render_partial_with_options options.merge(collection: object) }
  else
    locals = ::Hash[options[:as], object]
    _scope{ _render_partial_with_options options.merge(locals: locals) }
  end
  set! name, value
end

def _write_fragment_cache(key, options = nil)

def _write_fragment_cache(key, options = nil)
  @context.controller.instrument_fragment_cache :write_fragment, key do
    yield.tap do |value|
      ::Rails.cache.write(key, value, options)
    end
  end
end

def array!(collection = [], *args)

def array!(collection = [], *args)
  options = args.first
  if args.one? && _partial_options?(options)
    partial! options.merge(collection: collection)
  else
    super
  end
end

def cache!(key=nil, options={})

end
json.extract! @person, :name, :age
json.cache! ['v1', @person], expires_in: 10.minutes do

Example:

method in `ActionView::Helpers::CacheHelper` and so can be used in the same way.
Caches the json constructed within the block passed. Has the same signature as the `cache` helper
def cache!(key=nil, options={})
  if @context.controller.perform_caching
    value = _cache_fragment_for(key, options) do
      _scope { yield self }
    end
    merge! value
  else
    yield
  end
end

def cache_if!(condition, *args, &block)

end
json.extract! @person, :name, :age
json.cache_if! !admin?, @person, expires_in: 10.minutes do

Example:

the same way.
signature as the `cache` helper method in `ActionView::Helpers::CacheHelper` and so can be used in
Conditionally caches the json depending in the condition given as first parameter. Has the same
def cache_if!(condition, *args, &block)
  condition ? cache!(*args, &block) : yield
end

def cache_root!(key=nil, options={})

# json.extra 'This will not work either, the root must be exclusive'

end
json.extract! @person, :name, :age
json.cache_root! @person do

Example:

use this approach to cache deeper inside the hierarchy, like in partials or such. Continue to use #cache! there.
faster, but the drawback is that it only works, as the name hints, at the root. So you cannot
Caches the json structure at the root using a string rather than the hash structure. This is considerably
def cache_root!(key=nil, options={})
  if @context.controller.perform_caching
    ::Kernel.raise "cache_root! can't be used after JSON structures have been defined" if @attributes.present?
    @cached_root = _cache_fragment_for([ :root, key ], options) { yield; target! }
  else
    yield
  end
end

def initialize(context, *args)

def initialize(context, *args)
  @context = context
  @cached_root = nil
  super(*args)
end

def partial!(*args)


json.comments @post.comments, partial: "comments/comment", as: :comment, cached: true

json.array! @posts, partial: "posts/post", as: :post, cached: true

Example:

effectively using the multi fetch feature.
Aside from that, the `:cached` options is available on Rails >= 6.0. This will cache the rendered results

json.comments @post.comments, partial: 'comments/comment', as: :comment
# or:

json.partial! partial: 'posts/post', collection: @posts, as: :post
# or:

json.partial! 'posts/post', collection: @posts, as: :post
# or:

json.array! @posts, partial: 'posts/post', as: :post

Example:

There are multiple ways to generate a collection of elements as JSON, as ilustrated below:

json.partial! 'comments/comments', comments: @message.comments

Example:

comments, which can be used inside the partial.
the file `views/comments/_comments.json.jbuilder`, and set a local variable comments with all this message's
Generates JSON using the template specified with the `:partial` option. For example, the code below will render
def partial!(*args)
  if args.one? && _is_active_model?(args.first)
    _render_active_model_partial args.first
  else
    _render_explicit_partial(*args)
  end
end

def set!(name, object = BLANK, *args)

def set!(name, object = BLANK, *args)
  options = args.first
  if args.one? && _partial_options?(options)
    _set_inline_partial name, object, options
  else
    super
  end
end

def target!

def target!
  @cached_root || super
end