I'm trying to call a view helper from a custom RedCloth tag and am having absolutely no luck at all. All of the examples I can find have the custom tag method create and return a literal string without calling any other method at all.

I am trying to create a custom RedCloth tag to output a weekly schedule; the code for which has already been written in a helper as it is also used in other areas of the application.

So here's the (massively reduced) code that my problem boils down to:

app/views/page/show.html.erb:

<%= raw redcloth @page.content %

app/helpers/pages_helper.rb:

module PagesHelper
  def redcloth(content)
    r = RedCloth.new content
    r.extend ScheduleTag
    r.to_html
  end
end

app/helpers/schedule_tag.rb:

module ScheduleTag
  include ScheduleHelper

  def schedule(options)
    build_schedule
  end
end

app/helpers/schedule_helper.rb:

module ScheduleHelper
  def build_schedule
    content_tag :div do
      content_tag :span,
                  "Why won't my helper just work by magic like the rest of " \
                  "rails seems to?"
    end
  end
end

When executed, rails claims the following:

TypeError in Pages#show

Showing /blah/blah/blah/app/views/pages/show.html.erb where line #1 raised:

can't convert Symbol into Integer
Extracted source (around line #1):

1: <%= raw redcloth @page.content %>
Rails.root: /blah/blah/blah

Application Trace | Framework Trace | Full Trace
app/helpers/schedule_helper.rb:3:in `build_schedule'
app/helpers/schedule_tag.rb:42:in `schedule'
app/helpers/pages_helper.rb:22:in `redcloth'
app/views/pages/show.html.erb:1:in  _app_views_pages_show_html_erb___756530284_81829440__535015588'
app/controllers/pages_controller.rb:23:in `show'

I can make a little bit of progress by changing from using a helper to a class, but that class is still having issues using the standard helpers:

/app/helpers/schedule_builder.rb:

class ScheduleBuilder
  extend ActionView::Helpers::TagHelper

  def self.build_schedule
    content_tag :div do
      content_tag :span,
                  "Why won't my helper just work by magic like the rest of " \
                  "rails seems to?"
    end
  end
end

And rails says:

NoMethodError in Pages#show

Showing /blah/blah/blah/app/views/pages/show.html.erb where line #1 raised:

undefined method `output_buffer=' for ScheduleBuilder:Class
Extracted source (around line #1):

1: <%= raw redcloth @page.content %>
Rails.root: /blah/blah/blah

Application Trace | Framework Trace | Full Trace
app/helpers/schedule_builder.rb:5:in `build_schedule'
app/helpers/schedule_tag.rb:42:in `schedule'
app/helpers/pages_helper.rb:22:in `redcloth'
app/views/pages/show.html.erb:1:in  `_app_views_pages_show_html_erb___756530284_81708830__535015588'
app/controllers/pages_controller.rb:23:in `show'

So what am I to do? Am I missing something completely obvious and ought to bury my head in shame, or is it simply not possible to call helpers from anywhere one fancies? Do I need to just suck it up and get the custom tag to duplicate all of the code in my ScheduleHelper module?

Any help would be greatly appreciated.

有帮助吗?

解决方案

Okay, so I've come to an acceptable solution myself. So I'll be a good little boy and share.

Instead of a helper, I'm going to use a class that renders a partial, so the question should really become: "Calling partials from custom RedCloth tags".

(I've not commented the code, it should be pretty self documenting)

app/helpers/schedule_tag.rb:

module ScheduleTag
  def schedule(options)
    Schedule.new.render Date.today.monday
  end
end

app/helpers/schedule.rb:

class Schedule < ActionView::Base
  include ActionView::Helpers::TagHelper
  include Rails.application.routes.url_helpers

  def render week
    self.view_paths = "app/views"
    super :partial => "schedule/schedule",
          :locals => { :week => week,
                       :schedule => ScheduledClass.get_schedule(week) }
  end
end

app/view/schedule/_schedule.html.erb:

<table id="schedule">
  <tbody>
    <tr>
      <td>Hoop-dee-doo, it works!</td>
      <%= content_tag :td do %>
        <%= link_to "so do tag & route helpers", happy_monkey_path(:happy => "very") %>
      <% end %>
    </tr>
  </tbody>
</table>

As a slight aside, if you were to try this you may stumble upon the problem of RedCloth escaping your options string. Just enclose the options within =='s to get it to pass the options literally through. eg schedule. =={"weeks":["this","next"]}==. This may be a little on the dangerous side, so be sure to check for nastyness.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top