为什么这是ERB的错误?

时间:2013-06-28 21:55:47

标签: ruby erb

<div class='row'>
  <%= form.field_container :name do %>
    <%= form.label :name, raw('Name' + content_tag(:span, ' *', :class => 'required')) %>
    <%= form.text_field :name, :class => 'fullwidth' %>
    <%= form.error_message_on :name %>
  <% end %>
</div>

为什么会产生以下错误?

$ erb -x -T - test.erb | ruby -c
-:3: syntax error, unexpected ')'
...form.field_container :name do ).to_s); _erbout.concat "\n"
...                               ^
-:9: syntax error, unexpected $end, expecting ')'

2 个答案:

答案 0 :(得分:13)

如果查看erb -x -T - test.erb输出的代码:

#coding:ASCII-8BIT
_erbout = ''; _erbout.concat "<div class='row'>\n  "
; _erbout.concat(( form.field_container :name do ).to_s); _erbout.concat "\n"
; _erbout.concat "    "; _erbout.concat(( form.label :name, raw('Name' + content_tag(:span, ' *', :class => 'required')) ).to_s); _erbout.concat "\n"
; _erbout.concat "    "; _erbout.concat(( form.text_field :name, :class => 'fullwidth' ).to_s); _erbout.concat "\n"
; _erbout.concat "    "; _erbout.concat(( form.error_message_on :name ).to_s); _erbout.concat "\n"
; _erbout.concat "  ";  end ; _erbout.concat "\n"
; _erbout.concat "</div>\n"
; _erbout.force_encoding(__ENCODING__)

您可以在第三行看到do后跟)。 Ruby期待do ... end块,但得到一个右括号。这是语法错误的直接原因。

erb输出错误代码的原因是,当您使用<%=时,您正在使用<%。将代码更改为此修复了语法错误:

<div class='row'>
  <% form.field_container :name do %>
    <%= form.label :name, raw('Name' + content_tag(:span, ' *', :class => 'required')) %>
    <%= form.text_field :name, :class => 'fullwidth' %>
    <%= form.error_message_on :name %>
  <% end %>
</div>

我无法运行此代码来测试它是否在我的更改后输出它应该输出的内容,但erb生成的代码看起来会起作用:

#coding:ASCII-8BIT
_erbout = ''; _erbout.concat "<div class='row'>\n  "
;  form.field_container :name do ; _erbout.concat "\n"
; _erbout.concat "    "; _erbout.concat(( form.label :name, raw('Name' + content_tag(:span, ' *', :class => 'required')) ).to_s); _erbout.concat "\n"
# more...

修改

由于此解决方案显然确实打破了输出,因此我查看了mu is too short建议的内容。我检查了Erubis Rails 3 uses by default,其行为与ERB不同。 erubis -x -T - test.erb输出的代码(原始未经编辑的test.erb):

_buf = ''; _buf << '<div class=\'row\'>
  '; _buf << ( form.field_container :name do ).to_s; _buf << '
'; _buf << '    '; _buf << ( form.label :name, raw('Name' + content_tag(:span, ' *', :class => 'required')) ).to_s; _buf << '
'; _buf << '    '; _buf << ( form.text_field :name, :class => 'fullwidth' ).to_s; _buf << '
'; _buf << '    '; _buf << ( form.error_message_on :name ).to_s; _buf << '
';   end 
 _buf << '</div>
';
_buf.to_s

第三行有完全相同的问题,erubis -x -T - test.erb | ruby -c输出相同的语法错误。所以ERB和Erubis之间的差异可能不是问题。

我还尝试使用语法检查这段代码from the official Rails documentation

<%= form_for(zone) do |f| %>
  <p>
    <b>Zone name</b><br />
    <%= f.text_field :name %>
  </p>
  <p>
    <%= f.submit %>
  </p>
<% end %>

它得到相同的语法错误。所以并不是你的ERB代码写得不好;你的代码与那个例子非常相似。

此时我最好的猜测是erb的{​​{1}}标志,它将ERB模板转换为Ruby代码而不是直接评估它,是有缺陷的,并且不支持它应该具备的一些功能。虽然现在我考虑到了这一点,但是当你输出一个本身输出文本应该有效的块的结果时,我很难想象确切地输出Ruby代码应该。在什么时候应该写出每个输出 - 首先是结果,还是先写出块内容?

答案 1 :(得分:11)

简短版:没有错; Rails做了一些疯狂的事情。

长版:你只能做

<%= some_method do %>
<% end %>

(也就是说,使用带有块的<%=)因为Rails中存在巨大的飞行攻击。 <%= %>的内容应该是一个独立的表达式(或表达式):您应该能够将其粘贴到eval并使其在语法上有效。< / p>

在Rails 3之前,人们有时会被“正常帮助者”(link_tonumber_to_currency等)所困扰,你必须使用<%=,但在使用时这些帮助者或帮助者(例如form_for)的阻止形式,您必须使用<%。这就是Rails 3使<%=支持块的原因。

要处理这种情况下的块,当你使用<%=时,Rails会查看ERB代码,通过使用正则表达式查看它是否看起来像块,以及它是否会立即重写生成的代码把它变成有效的Ruby。

优秀博客文章“Block Helpers in Rails 3”中的更多血腥细节。