AshDispatch.SafeRender (AshDispatch v0.5.0)

View Source

HTML-safe rendering helpers for AshDispatch.TemplateResolver.

When TemplateResolver renders an email.html.heex template it preprocesses HEEx-style {@var} markers into <%= @var %> and evaluates the result via EEx.eval_string/2. Plain EEx does not HTML-escape interpolated values, so any user-controlled string flowing through prepare_template_assigns/2 (lead name, contract recipient, customer comment, etc.) would land raw in the rendered email — a real injection vector.

The preprocessor wraps every auto-converted {@var} expansion in AshDispatch.SafeRender.escape/1 for HTML formats so escaping is the default, matching Phoenix HEEx semantics.

Opt-out (when you genuinely have safe markup)

<p>{AshDispatch.SafeRender.raw @already_safe_html}</p>

raw/1 returns its argument unchanged and is recognized as a "not a bare @var" expression by the preprocessor, so it's emitted as plain <%= raw(@x) %> without the escape wrapper.

Phoenix.HTML interop

If an assign value is a {:safe, iodata} tuple (Phoenix's Phoenix.HTML.Safe output) escape/1 returns the iodata as-is — the value already promises it is escaped.

Summary

Functions

Escape a value for safe inclusion in HTML output.

Mark a value as already-safe HTML so the preprocessor's auto-escape is bypassed.

Functions

escape(value)

@spec escape(any()) :: iodata()

Escape a value for safe inclusion in HTML output.

  • nil"" (so {@missing_field} doesn't render the string "nil")
  • binary → HTML-escaped
  • integer / float / atom → string-converted (no escape needed — these can't contain markup characters that change meaning)
  • {:safe, iodata} → returned unchanged (already escaped by caller)
  • Anything else → to_string/1 then escape

raw(value)

@spec raw(value) :: value when value: any()

Mark a value as already-safe HTML so the preprocessor's auto-escape is bypassed.

In templates:

<p>{AshDispatch.SafeRender.raw @trusted_html}</p>

Returns its argument unchanged — the wrapper is only meaningful as a signal to the HEEx preprocessor, which sees raw(@x) is not a bare @var and emits <%= raw(@x) %> without escape.