Class: PbbuilderTemplate

Inherits:
Pbbuilder show all
Defined in:
lib/pbbuilder/template.rb

Overview

PbbuilderTemplate is an extension of Pbbuilder to be used as a Rails template It adds support for partials.

Class Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Pbbuilder

#attributes!, #extract!, #merge!, #method_missing, #new_message_for, #respond_to_missing?, #target!

Constructor Details

#initialize(context, message) ⇒ PbbuilderTemplate

Returns a new instance of PbbuilderTemplate.



14
15
16
17
# File 'lib/pbbuilder/template.rb', line 14

def initialize(context, message)
  @context = context
  super(message)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Pbbuilder

Class Attribute Details

.template_lookup_optionsObject

Returns the value of attribute template_lookup_options.



9
10
11
# File 'lib/pbbuilder/template.rb', line 9

def template_lookup_options
  @template_lookup_options
end

Instance Method Details

#cache!(key = nil, options = {}) ⇒ Object

Caches fragment of message. Can be called like the following: ‘pb.cache! “cache-key” do; end’ ‘pb.cache! “cache-key”, expire_in: 1.min do; end’

Parameters:

  • key (defaults to: nil)

    String

  • options (defaults to: {})

    Hash

Returns:

  • nil



95
96
97
98
99
100
101
102
103
104
105
# File 'lib/pbbuilder/template.rb', line 95

def cache!(key=nil, options={})
  if @context.controller.perform_caching
    value = _cache_fragment_for(key, options) do
      _scope(target!) { yield self }.to_h.compact_blank
    end

    merge! value
  else
    yield
  end
end

#cache_if!(condition, *args, &block) ⇒ Object

Conditionally caches the protobuf message depending on the condition given as first parameter. Has the same signature as the cache helper method in ActionView::Helpers::CacheHelper and so can be used in the same way.

Example:

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


116
117
118
# File 'lib/pbbuilder/template.rb', line 116

def cache_if!(condition, *args, &block)
  condition ? cache!(*args, &block) : yield
end

#partial!(*args) ⇒ Object

Render a partial. Can be called as: pb.partial! “name/of_partial”, argument: 123 pb.partial! “name/of_partial”, locals: 123 pb.partial! partial: “name/of_partial”, argument: 123 pb.partial! partial: “name/of_partial”, locals: 123 pb.partial! @model # @model is an ActiveModel value, it will use the name to look up a partial



25
26
27
28
29
30
31
# File 'lib/pbbuilder/template.rb', line 25

def partial!(*args)
  if args.one? && _is_active_model?(args.first)
    _render_active_model_partial args.first
  else
    _render_explicit_partial(*args)
  end
end

#set!(field, *args, **kwargs, &block) ⇒ Object



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/pbbuilder/template.rb', line 33

def set!(field, *args, **kwargs, &block)
  # If partial options are being passed, we render a submessage with a partial
  if kwargs.has_key?(:partial)
    if args.one? && kwargs.has_key?(:as)
      # pb.friends @friends, partial: "friend", as: :friend
      # Call set! on the super class, passing in a block that renders a partial for every element
      super(field, *args) do |element|
        _set_inline_partial(element, kwargs)
      end
    elsif kwargs.has_key?(:collection) && kwargs.has_key?(:as)
      # pb.friends partial: "racers/racer", as: :racer, collection: [Racer.new(1, "Johnny Test", []), Racer.new(2, "Max Verstappen", [])]
      # collection renderer
      options = kwargs.deep_dup

      options.reverse_merge! locals: options.except(:partial, :as, :collection, :cached)
      options.reverse_merge! ::PbbuilderTemplate.template_lookup_options

      collection = options[:collection] || []
      partial = options[:partial]

      # The way recursive rendering works is that CollectionRenderer needs to be aware of node its currently rendering and parent node,
      # these is no need to know entire "stack" of nodes. CollectionRenderer would traverse to bottom node render that first and then go up in stack.

      # CollectionRenderer uses locals[:pb] to render the partial as a protobuf message,
      # but also needs locals[:pb_parent] to apply rendered partial to top level protobuf message.

      # This logic could be found in CollectionRenderer#build_rendered_collection method that we over wrote.
      options[:locals].merge!(pb: ::PbbuilderTemplate.new(@context, new_message_for(field)))
      options[:locals].merge!(pb_parent: self)
      options[:locals].merge!(field: field)

      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(message[field.to_s],&block) }
        .render_collection_with_partial(collection, partial, @context, nil)
    else
      # pb.best_friend partial: "person", person: @best_friend
      # Call set! as a submessage, passing in the kwargs as partial options
      super(field, *args) do
        _render_partial_with_options(kwargs)
      end
    end
  else
    super
  end
end