Почему это ошибка с 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 ответов


если вы посмотрите на код, выдаваемых 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__)

вы можете видеть, что на третьей строке, a do после ). Руби ожидает do...end блок, но получает закрывающую скобку. Это непосредственная причина ошибки.

причина erb outtputting плохой код, что вы используете <%= когда вы должны использовать <%. Изменение кода на this исправляет синтаксис ошибка:

<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 слишком короткий предложил. Я проверил, если erubis аппликации, который Rails 3 используется по умолчанию, ведет себя иначе, чем ERB. Выведенный код by 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, вероятно, не являются проблемой.

Я также попробовал синтаксис-проверка этого фрагмента кода из официальной документации Rails:

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

он получает ту же ошибку синтаксиса. Так что дело не в том, что ваш код ERB плохо написан; ваш код очень похож к этому примеру.

на данный момент мое лучшее предположение, что erb ' s -x флаг, который переводит шаблон ERB в код Ruby вместо того, чтобы оценивать его напрямую, имеет недостатки и не поддерживает некоторые функции, которые он должен. Хотя теперь, когда я думаю об этом, мне трудно представить, что именно Ruby code должны выводится при выводе результата блока, который сам выводит текст должен работать. В какое время должен быть записан каждый из выходов – сначала результат или содержимое блока?


короткая версия: ничего не случилось; Rails делает некоторые сумасшедшие вещи.

длинная версия: вы можете только сделать

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

(то есть, использовать <%= С блоком) из-за гигантского летающего взлома в рельсах. Содержание <%= %> предполагается, что это выражение (или выражения), которое стоит само по себе: вы должны быть в состоянии вставить его в eval и это будет синтаксически правильным.

перед рельсами 3, Люди иногда были смущены тем фактом, что с "нормальными помощниками" (link_to, number_to_currency, etc.), вы должны использовать <%=, но при использовании блочной формы этих помощников или помощников, таких как form_for, вы должны использовать <%. Вот почему Rails 3 сделал <%= поддержка блоков.

для обработки блоков в этом случае, когда вы используете <%=, Rails смотрит на код ERB, видит, выглядит ли он как блок с помощью регулярного выражения, и если он переписывает сгенерированный код на лету, чтобы превратить его в действительный Ruby.

больше кровавые подробности в отличном блоге"блок помощников в Rails 3".