非Rails环境下如何让ERB/ERUBI默认转义模板变量HTML而非全模板转义
解决方案
要实现Rails风格的ERB默认HTML转义(<%= %>自动转义变量,保留模板本身的HTML结构),可以通过自定义ERB上下文或扩展Tilt模板类来实现,以下是具体方法:
方法一:自定义ERB上下文类
通过重写ERB的输出逻辑,让<%= %>自动调用HTML转义方法,同时提供raw方法输出未转义内容:
require 'erb' require 'erb/util' class ERBSafeContext include ERB::Util def initialize(variables = {}) variables.each do |key, value| instance_variable_set("@#{key}", value) end @_erbout = +'' end # 重写concat方法,自动转义非安全内容 def concat(value) if value.is_a?(ERB::Util::HTMLSafeString) @_erbout << value else @_erbout << html_escape(value) end end # 标记内容为安全,跳过转义 def raw(value) ERB::Util.html_safe(value.to_s) end def render(template_path) template = ERB.new(File.read(template_path), trim_mode: '-') template.result(binding) end end
使用示例
假设file.html.erb模板内容:
<h1>用户名称</h1> <p>转义后的输出:<%= name %></p> <p>原始HTML输出:<%= raw(name) %></p>
渲染代码:
context = ERBSafeContext.new(name: '<b>Pat</b>') puts context.render('file.html.erb')
输出结果:
<h1>用户名称</h1> <p>转义后的输出:<b>Pat</b></p> <p>原始HTML输出:<b>Pat</b></p>
方法二:扩展Tilt模板类
如果你需要继续使用Tilt工具,可以扩展其ERB模板类,修改默认渲染逻辑:
require 'tilt' require 'erb/util' class SafeERBTemplate < Tilt::ERBTemplate def prepare @engine = ERB.new(data, options[:safe], options[:trim_mode], '@_erbout') @engine.def_method(@scope, :render) do |*args| variables = args.first || {} variables.each { |k, v| instance_variable_set("@#{k}", v) } @_erbout = +'' # 注入转义逻辑 def concat(value) if value.is_a?(ERB::Util::HTMLSafeString) @_erbout << value else @_erbout << ERB::Util.html_escape(value) end end def raw(value) ERB::Util.html_safe(value.to_s) end eval(@engine.src) @_erbout end end end # 将自定义模板注册到Tilt Tilt.register SafeERBTemplate, 'erb'
使用示例
template = Tilt.new('file.html.erb') puts template.render(nil, name: '<b>Pat</b>')
输出效果和方法一完全一致,模板本身的HTML保持不变,变量输出自动转义。
说明
你之前使用Tilt.new("file.html.erb", escape_html: true)无效的原因是:该选项会转义整个模板的所有内容(包括模板里的原生HTML标签),而不是仅转义<%= %>输出的变量,因此不符合需求。
内容的提问来源于stack exchange,提问作者davetron5000
相关产品推荐
相关产品推荐

