Class: LexxyVariables::Resolver

Inherits:
Object
  • Object
show all
Defined in:
lib/lexxy_variables/resolver.rb

Overview

Resolves the attachment chips in stored rich text, returning a new ActionText::Content with every chip replaced by its value. The result is a plain content object, so Action Text's own conversions chain from it: #to_s (sanitized HTML), #to_plain_text, #to_markdown, #to_html.

Security invariants (do not weaken):

1. A random per-render nonce guards placeholder tokens, so an author cannot
 forge a substitution by typing the token pattern into the body.
2. Resolved values are injected as DOM text nodes, never parsed as markup.
 HTML serialization escapes them, and the sanitizer still runs when the
 content is rendered. :html output is spliced as markup here, before that
 render-time sanitization, so the sanitizer cleans it too.
3. Any template-engine parsing (Liquid) sees only chip keys, never body text.

Build a fresh Resolver per call. #call stores per-render state on the instance.

Instance Method Summary collapse

Constructor Details

#initialize(config = LexxyVariables.config) ⇒ Resolver

Returns a new instance of Resolver.



18
19
20
# File 'lib/lexxy_variables/resolver.rb', line 18

def initialize(config = LexxyVariables.config)
  @config = config
end

Instance Method Details

#call(content, context: nil, locale: nil, assigns: {}) ⇒ Object



22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/lexxy_variables/resolver.rb', line 22

def call(content, context: nil, locale: nil, assigns: {})
  @context = context
  @nonce = SecureRandom.hex(8)
  @used_keys = []

  I18n.with_locale(locale || I18n.locale) do
    fragment = substitute(content.fragment, 0)
    resolved = @config.resolve_assigns(@context, @used_keys.uniq)
    resolved = resolved.merge(assigns.transform_keys(&:to_s)) if assigns.any?
    inject_values(fragment, resolved)
    ActionText::Content.new(fragment, canonicalize: false)
  end
end