【问题标题】:Why is this an error with ERB?为什么这是 ERB 的错误?
【发布时间】:2013-06-28 21:55:46
【问题描述】:
<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 ')'

【问题讨论】:

标签: ruby erb


【解决方案1】:

如果你看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 期待一个 doend 块,但得到一个右括号。这就是语法错误的直接原因。

erb 输出错误代码的原因是你使用了&lt;%=,而你应该使用&lt;%。将代码更改为此可以修复语法错误:

<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 的建议。我检查了ErubisRails 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-x 标志,它将 ERB 模板转换为 Ruby 代码而不是直接评估它,它有缺陷,并且不支持它应该支持的某些功能。虽然现在我想起来了,但是当你输出一个本身输出文本的块的结果应该工作时,我很难想象究竟应该输出什么 Ruby 代码应该。每个输出应该在什么时候被写入——首先是结果,还是首先写入块内容?

【讨论】:

  • @DanielFischer 我不确定form.field_container 是否应该将值返回到输出。既然你说是,那么&lt;%=确实是你想要的,所以解决办法一定是别的。
【解决方案2】:

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

长版:你只能这样做

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

(也就是说,使用 &lt;%= 和块)因为 Rails 中有一个巨大的飞行黑客。 &lt;%= %&gt; 的内容应该是一个独立的表达式(或多个表达式):您应该能够将其粘贴到 eval 并使其在语法上有效。

在 Rails 3 之前,人们有时会因为使用“普通助手”(link_tonumber_to_currency 等)必须使用 &lt;%= 而感到困惑,但是当使用这些助手的块形式时或像form_for 这样的助手,你必须使用&lt;%。这就是 Rails 3 制作 &lt;%= 支持块的原因。

为了在这种情况下处理块,当您使用&lt;%= 时,Rails 会查看 ERB 代码,使用正则表达式查看它是否看起来像块,如果确实如此,则动态重写生成的代码以转将其转换为有效的 Ruby。

精彩博文“Block Helpers in Rails 3”中有更多血腥细节。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-24
    相关资源
    最近更新 更多