RJSの中でform_remote_tagを使おうとして挫折しましたというお話。
page.replace_htmlで書き換えるHTMLにformを含みたかったのが事の発端。
いつもRHTMLの中で使うように
<% form_remote_tag :url => '/posts' do -%>
<div><%= submit_tag 'Save' %></div>
<% end -%>
をそのまま
form_remote_tag :url => '/posts' do
"<div>#{ submit_tag 'Save' }</div>"
end
のようにしてやったのだけれどダメ。ブロックの中身が出てこない。
しかもdevelopmentだというのにログにもさっぱり。
黙ってないでなにか言ったらどうなのだとばかりにRailsのソースへ・・・。
で、
actionpack-1.13.6/lib/action_view/helpers/prototype_helper.rb
172 def form_remote_tag(options = {}, &block)
173 options[:form] = true
...
180 form_tag(options[:html].delete(:action) || url_for(options[:url]), options[:html], &block)
181 end
ブロックはそのままform_tag()に渡っている。
actionpack-1.13.6/lib/action_view/helpers/form_tag_helper.rb
33 def form_tag(url_for_options = {}, options = {}, *parameters_for_url, &block)
34 html_options = options.stringify_keys
...
50 if block_given?
51 content = capture(&block)
52 concat(tag(:form, html_options, true) + method_tag, block.binding)
53 concat(content, block.binding)
54 concat("</form>", block.binding)
55 else
56 tag(:form, html_options, true) + method_tag
57 end
58 end
このへん怪しいってことで50~55行目の間、地味にputsをはさんで流れを調べた結果、途中で例外が投げられてるみたい。
56 tag(:form, html_options, true) + method_tag
57 end
58 rescue
59 p $!
60 end
すかさずこう(form_tag()全体にrescue)して捕まえてみたら
#<NameError: undefined local variable or method `_erbout' for #<#<Class:0xb7046944>:0xb704691c>>
なんぞこれ。
これが出ているのは
actionpack-1.13.6/lib/action_view/helpers/text_helper.rb
25 def concat(string, binding)
26 eval("_erbout", binding).concat(string)
27 end
しかし、_erboutのスコープがどうなっているのかがさっぱりわからない。
RJSとRHTMLの違いを探しにrespond_toのところ(mime_responds.rb)を読みに行ったがもっとカオスだった。
たぶんblock.bindingだとかがちゃんと読めれば分かるのだろうけど。(希望的観測)
・・・
くっ!ブロックの理解が足りない!