When using Liquid templates in Rails (for emails, user-generated content, etc.), you'll often need custom filters. Here's how to add them.
How Liquid Filters Work
Filters transform values using the pipe | syntax:
{{ "hello" | upcase }} → "HELLO"
{{ 1000 | money }} → "$1,000.00"
{{ 'greeting' | t }} → "Hello!" (i18n)
The value before the pipe becomes the first argument to your filter method.
Docs: https://shopify.github.io/liquid/basics/introduction/#filters
Creating a Custom Filter
Define the Filter Module
# lib/liquid_i18n_filter.rb
module LiquidI18nFilter
def t(key, options = {})
I18n.t(key, **options.symbolize_keys)
end
end
Liquid::Template.register_filter(LiquidI18nFilter)
Load It at Boot
# config/initializers/liquid_filters.rb
require Rails.root.join('lib/liquid_i18n_filter')
That's it. The filter is now available globally in all Liquid templates.
Usage
{{ 'hello_world' | t }}
{{ 'welcome_user' | t: name: user.name }}
How Arguments Map
| Liquid | Ruby Method Call |
|------------------------|-------------------------|
| {{ x | foo }} | foo(x) |
| {{ x | foo: a }} | foo(x, a) |
| {{ x | foo: a, b: 1 }} | foo(x, a, { "b" => 1 }) |
Practical Example: Currency Filter
# lib/liquid_currency_filter.rb
module LiquidCurrencyFilter
def money(cents, currency = 'USD')
Money.new(cents, currency).format
end
end
Liquid::Template.register_filter(LiquidCurrencyFilter)
{{ product.price_cents | money }} → "$19.99"
{{ product.price_cents | money: 'EUR' }} → "€19.99"
Key Points
- Global registration —
register_filtermakes it available to all templates - First argument — Value before | is always the first parameter
- Named arguments — Passed as a hash (strings keys, call
.symbolize_keysif needed) - No instance state — Filters are stateless; use method arguments only