You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby ERB类报"未定义局部变量或方法"错误,但erb命令解析正常

ERB模板用erb命令正常执行,但Ruby ERB类调用报错undefined local variable or method 'i'

问题重现

有如下test.erb模板:

% for i in 0..1
  foo<%=i%>;
% end

用系统自带的erb命令运行完全正常:

$ erb test.erb
    foo0;
    foo1;

但用Ruby代码直接调用ERB类执行时,却抛出变量未定义的错误:

test.rb代码:

require 'erb'

e = ERB.new(File.read("test.erb"))
File.open("test.out", 'w') do |f|
    f.write e.result(binding)
end

运行后报错(Ruby 1.9.1及更高版本错误信息类似):

$ ruby test.rb
(erb):2:in `block in <main>': undefined local variable or method `i' for main:Object (NameError)
        from <...>/lib/ruby/1.9.1/erb.rb:838:in `eval'
        from <...>/lib/ruby/1.9.1/erb.rb:838:in `result'
        from test.rb:5:in `block in <main>'
        from test.rb:4:in `open'
        from test.rb:4:in `<main>'

问题原因

erb命令默认启用了特殊的trim_mode编译选项,内部模板编译逻辑会自动处理循环变量的作用域。而直接调用ERB.new时,默认编译方式会将模板内的循环变量i隔离在局部代码块中,我们传递的binding属于外部主作用域,导致模板无法找到这个变量。

解决思路

方案1:给ERB实例添加trim_mode: '-'参数

初始化ERB对象时指定trim_mode: '-',该选项会调整模板编译规则,让循环变量能被正确识别:

require 'erb'

# 启用trim_mode的'-'模式
e = ERB.new(File.read("test.erb"), trim_mode: '-')
File.open("test.out", 'w') do |f|
    f.write e.result(binding)
end

方案2:提前在作用域中声明变量(不推荐)

在调用result(binding)之前,在当前作用域提前声明i变量(哪怕只是赋值为nil),让ERB编译时能识别到该变量的存在:

require 'erb'

i = nil # 提前声明变量
e = ERB.new(File.read("test.erb"))
File.open("test.out", 'w') do |f|
    f.write e.result(binding)
end

这种方式不够优雅,模板内的循环变量理应由模板自身管理,因此优先推荐方案1。

方案3:使用result_with_hash方法(Ruby 2.5+)

如果你的Ruby版本在2.5及以上,可以使用result_with_hash方法,无需传递binding,直接传空哈希即可,模板内部的变量会在独立作用域中处理:

require 'erb'

e = ERB.new(File.read("test.erb"))
File.open("test.out", 'w') do |f|
    f.write e.result_with_hash({})
end

内容的提问来源于stack exchange,提问作者user20183737

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 16:50:22