lib/jbuilder/jbuilder_template.rb in jbuilder-2.11.2 vs lib/jbuilder/jbuilder_template.rb in jbuilder-2.11.3

- old
+ new

@@ -1,6 +1,7 @@ require 'jbuilder/jbuilder' +require 'jbuilder/collection_renderer' require 'action_dispatch/http/mime_type' require 'active_support/cache' class JbuilderTemplate < Jbuilder class << self @@ -13,10 +14,42 @@ @context = context @cached_root = nil super(*args) end + # Generates JSON using the template specified with the `:partial` option. For example, the code below will render + # the file `views/comments/_comments.json.jbuilder`, and set a local variable comments with all this message's + # comments, which can be used inside the partial. + # + # Example: + # + # json.partial! 'comments/comments', comments: @message.comments + # + # There are multiple ways to generate a collection of elements as JSON, as ilustrated below: + # + # Example: + # + # json.array! @posts, partial: 'posts/post', as: :post + # + # # or: + # json.partial! 'posts/post', collection: @posts, as: :post + # + # # or: + # json.partial! partial: 'posts/post', collection: @posts, as: :post + # + # # or: + # json.comments @post.comments, partial: 'comments/comment', as: :comment + # + # Aside from that, the `:cached` options is available on Rails >= 6.0. This will cache the rendered results + # effectively using the multi fetch feature. + # + # Example: + # + # json.array! @posts, partial: "posts/post", as: :post, cached: true + # + # json.comments @post.comments, partial: "comments/comment", as: :comment, cached: true + # def partial!(*args) if args.one? && _is_active_model?(args.first) _render_active_model_partial args.first else _render_explicit_partial(*args) @@ -102,15 +135,34 @@ end private def _render_partial_with_options(options) - options.reverse_merge! locals: options.except(:partial, :as, :collection) + 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) + if options.key?(:collection) && (options[:collection].nil? || options[:collection].empty?) + array! + elsif as && options.key?(:collection) && CollectionRenderer.supported? + collection = options.delete(:collection) || [] + partial = options.delete(:partial) + options[:locals].merge!(json: self) + + if options.has_key?(:layout) + raise ::NotImplementedError, "The `:layout' option is not supported in collection rendering." + end + + if options.has_key?(:spacer_template) + raise ::NotImplementedError, "The `:spacer_template' option is not supported in collection rendering." + end + + CollectionRenderer + .new(@context.lookup_context, options) { |&block| _scope(&block) } + .render_collection_with_partial(collection, partial, @context, 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 @@ -160,15 +212,10 @@ ::ActiveSupport::Cache.expand_cache_key(key, :jbuilder) end def _fragment_name_with_digest(key, options) if @context.respond_to?(:cache_fragment_name) - # Current compatibility, fragment_name_with_digest is private again and cache_fragment_name - # should be used instead. @context.cache_fragment_name(key, **options) - elsif @context.respond_to?(:fragment_name_with_digest) - # Backwards compatibility for period of time when fragment_name_with_digest was made public. - @context.fragment_name_with_digest(key) else key end end