Module: EmailTemplate::MergeFields

Defined in:
app/models/email_template/merge_fields.rb

Overview

Which {{ root }} merge fields a template may reference.

Liquid renders with strict_variables: false
(app/lib/liquid/renderer.rb), so an unknown variable produces an empty
string — no exception, no log line, nothing at send time. A typo in a
CRM-edited template therefore ships a hole in a customer email and nobody
finds out. This registry is what EmailTemplate validates against so the
person editing the template hears about it at save time instead.

Origin: {{receipt_reference_number}} sat in the Check-payment branch of
PURCHASE_RECEIPT and AUTH_RECEIPT rendering blank — every sibling branch used
{{receipt_reference}}, and nothing in the codebase ever set the longer name.

Only enforced for templates carrying a system_code. Campaign templates
get ad-hoc merge options from whoever sends them, so there is no knowable
allowlist and validation would be noise.

Constant Summary collapse

GLOBAL =

Always supplied by CommunicationBuilder#merge_options, for every template.

%w[
  sender sender_party recipient recipient_party recipient_contact_points
  first_name salutation signature review_url uploads unsubscribe_url
  resource customer customer_number contact
  primary_sales_rep primary_sales_rep_signature
  interesting_fact years_at_warmlyyours certifications
  sender_photo_url sender_job_title sender_name sender_phone
  forloop
].freeze
RESOURCE =

options[resource.class.name.tableize.singularize] — the resource is
exposed under its own model name as well as under resource.

%w[
  article certification course_enrollment credit_application credit_memo
  customer customer_topic delivery exported_catalog_item_packet invoice
  locator_record opportunity order payment post purchase_order quote receipt
  rma rma_item room_configuration spiff_enrollment support_case
  support_case_participant
].freeze
BY_SYSTEM_CODE =

Extra merge options injected by a specific caller, keyed by system_code.
Add here when you add a merge_options:/@extra_merge_options key.

{
  'AUTH_RECEIPT' => %w[receipt_number receipt_date receipt_items payment_method
                       payment_amount card_type card_name auth_code
                       receipt_reference receipt_authorization_code receipt_amount],
  'PURCHASE_RECEIPT' => %w[receipt_number receipt_date receipt_items payment_method
                           payment_amount card_type card_name auth_code
                           receipt_reference receipt_authorization_code receipt_amount],
  'BLOG_CONFIRM' => %w[confirm_url],
  'BLOG_UPDATE' => %w[edition_date posts_content posts_toc recent_articles],
  'BULLETIN_CREATE' => %w[article],
  'BULLETIN_UPDATE' => %w[article],
  'CERT_INS_WARN' => %w[insurance_upload_url insurance_expiration_date deadline_date],
  'CERT_INS_FINAL' => %w[insurance_upload_url insurance_expiration_date deadline_date],
  'CERT_INS_LAPSED' => %w[insurance_upload_url insurance_expiration_date deadline_date],
  'LIAB_INSUR_EXPIRED' => %w[liability_insurance],
  'LIAB_INSUR_EXPIRES10' => %w[liability_insurance],
  'EXPORTED_CATALOG' => %w[token],
  'INVOICE_PAYMENT' => %w[receipt_link],
  'STATEMENTOFACCOUNT' => %w[account_receivable_email total_open_amount],
  'TOPICFOLLOWUP' => %w[summary],
  'WIRE_TRANSFER_INFO' => %w[order_reference order_total account_receivable_email],
  'PLAN_REQUEST_CONF' => %w[iq_rooms iq_room_ids]
}.freeze

Class Method Summary collapse

Class Method Details

.allowed_for(system_code) ⇒ Array<String>

Root merge fields this template is allowed to reference.

Parameters:

  • system_code (String, nil)

Returns:

  • (Array<String>)


71
72
73
# File 'app/models/email_template/merge_fields.rb', line 71

def self.allowed_for(system_code)
  GLOBAL + RESOURCE + BY_SYSTEM_CODE.fetch(system_code.to_s, [])
end

.referenced_roots(content) ⇒ Array<String>

Root {{ name }} identifiers referenced by a Liquid source string.
Names bound by {% for x in … %} are excluded — they're locals, not
merge fields.

Parameters:

  • content (String)

Returns:

  • (Array<String>)


81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'app/models/email_template/merge_fields.rb', line 81

def self.referenced_roots(content)
  return [] if content.blank?

  begin
    template = Liquid::ParseEnvironment.parse!(content)
  rescue Liquid::SyntaxError
    return [] # the syntax validation reports this; don't double-report
  end

  roots = Set.new
  walk(template.root, roots, Set.new)
  roots.to_a
end

.unknown_for(content, system_code) ⇒ Array<String>

Returns referenced roots that nothing will supply.

Returns:

  • (Array<String>)

    referenced roots that nothing will supply



96
97
98
99
100
# File 'app/models/email_template/merge_fields.rb', line 96

def self.unknown_for(content, system_code)
  return [] if system_code.blank?

  referenced_roots(content) - allowed_for(system_code)
end