#966 ✓resolved
Matt Jones

DRYML is incompatible with Rails 3 block helpers

Reported by Matt Jones | September 22nd, 2011 @ 11:08 PM | in Hobo 1.3 (Rails 3)

Summary:

The ERB parser used by DRYML doesn't support the new-style Rails block helpers. Using <% %> gets you no output, and using <%= %> creates invalid ERB.

Rails 3 patches in some changes to Erubis to enable this behavior; in particular, it avoids using parentheses around do |args| clauses.

One can try using the new parser in DRYML by changing one line in dryml_builder.rb:

erb = ERB.new(erb_src, nil, trim_mode, "output_buffer")
# changes to
erb = ActionView::TemplateHandlers::ERB.erb_implementation.new(erb_src, :trim => trim_mode)

However, this blows up disastrously when there are procs in ERB - in other words, anywhere DRYML uses the param mechanism.

There are additional potential issues (such as switching from output_buffer to @output_buffer) but this is certainly one of the biggest.

Comments and changes to this ticket

  • Matt Jones

    Matt Jones September 23rd, 2011 @ 02:14 AM

    Some further notes on this:

    • the patched version of Erubis that Rails uses makes use of @output_buffer, which isn't even in the right OBJECT when called in the functions in template.rb. I got a page to render by disabling all the taglibs and doing a src.gsub('@output_buffer', 'output_buffer') in the render_page function, but that's not a great solution.

    • the patched version triggers the fallback for block helpers (@output_buffer.append_if_string) any time it sniffs something that looks vaguely like a block. I got it to stop eating our proc calls by changing BLOCK_EXPR (in erb.rb) to (?<!proc)\s+(do|\{)(\s*\|[^|]*\|)?\s*\Z, but that requires negative lookbehind which is Ruby 1.9-only. It also still has problems when we create a line that starts with a bunch of brackets / parens and then has a new_context block. For instance, the account-page tag produces this line of ERB:

    " } }, }] }, \n            :password_confirmation_label => proc { [{}, { :default => proc { |_password_confirmation_label__default_content| new_context { "
    

    (less the quote marks), which turns into utter fail when Rails tacks @output_buffer.append_if_string= on the beginning.

    Need to evaluate this further - maybe we could do our own ERB parser? Or, failing that, fix block helpers when we do the "ERB scriptlets" translation?

  • Matt Jones
  • Matt Jones

    Matt Jones September 25th, 2011 @ 05:18 AM

    Alright, I've got a reasonable solution (commit above). Several caveats:

    • vanilla Rails complains if you mistakenly enclose a block helper in <% %> instead of <%= %>. The code to support this was the principal roadblock to working with DRYML, so the code doesn't do this. Thus, improperly bracketed block helpers will FAIL SILENTLY.

    • standard ERB partials mostly work - but they don't actually access the same set of instance variables as DRYML code does (plain ERB talks to the TemplateEnvironment view object). The variables will be the same if they were set in the controller, but changes will not propagate from one to the other. Use :locals; it's not just a best practice, it's the law!

    • replacing ActionView's ERB handler doesn't change Hobo's - very few people will want to do this, but worth noting.

  • Owen
  • Tim Griffin

    Tim Griffin October 14th, 2011 @ 04:27 AM

    Hi Matt;

    WRT to my recent posting on Hobo Users, I just noticed that edge Hobo 1.3 has a broken dev-user-changer. In my own code, I had to override the "<%" occurences with "<%=" to get the <select-menu> to include options. Does this seem right?

    (I don't have any other <select-menu> tags in my app so the dev-user-changer is the first I noticed!)

    <def tag="select-menu" attrs="options, selected, first-option, first-value, key">
    <%= key ||= 'default'
       %w[options first_option first_value].each do |a|
         str = t("tags.select_menu.#{key}.#{a}", :default=>'')
         eval "#{a} = str unless str.blank?"
       end
    -%>
      <select merge-attrs param="default">
        <%= selected=this if selected.nil? %>
        <option value="#{first_value}" unless="&first_option.nil?"><first-option/></option>
        <do param="options"><%= options_for_select(options, selected) %></do>
      </select>
    </def>
    
  • Tim Griffin

    Tim Griffin October 14th, 2011 @ 04:31 AM

    (I see now that I only needed to update the <%= where 'options_for_select' appears, not the others.)

  • Bryan Larsen

    Bryan Larsen October 22nd, 2011 @ 09:33 PM

    Arg, I didn't see your fix Tim and tracked this down independently. Oops. Now we just need to check to ensure that this same problem isn't elsewhere in Rapid.

  • Bryan Larsen
  • Bryan Larsen

    Bryan Larsen October 25th, 2011 @ 04:06 PM

    • State changed from “open” to “resolved”

    A quick audit of RAPID shows no other bugs of the type Tim found. I'm going to close this ticket and put out an RC PDQ. Reopen if you think there's more to do here.

  • Owen

    Owen October 25th, 2011 @ 04:51 PM

    Great. Thanks, Bryan.

Please Sign in or create a free account to add a new ticket.

With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.

New-ticket Create new ticket

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile ยป

Referenced by

Pages