Question

I'm using Rabl to generate XML output in a rake task:

xml = Rabl.render @listings, 'feeds/listings', :format => :xml
# do stuff with xml

However, I need to use multiple helper methods in the rabl view file referenced, and I keep getting a NoMethodError as I expected from the answer to this question.

I tried using extends and include in the class used by the rake task but I still get the same error on the helper methods:

require "#{Rails.root}/app/helpers/feeds_helper.rb"

class SerializeData
  extends FeedsHelper

  def perform
    xml = Rabl.render @listings, 'feeds/listings', :format => :xml
    # do stuff with xml
  end
end

My question is: is there any way to use helper methods in rabl view files generated in this way? (or at least in a way that I can still render them as a string in a rake task?) The helper methods are used many, many times to correctly format various data per fixed requirements, so it would be very difficult to remove them entirely.

Was it helpful?

Solution

I ended up with a monkey-patchy solution.

I noticed that the NoMethodFound error came from an instance of the Rabl::Engine class, so I included the needed routing and helper methods in that class and was then able to access them:

require "#{Rails.root}/app/helpers/feeds_helper.rb"
...
class Rabl::Engine
  include Rails.application.routes.url_helpers
  include FeedsHelper
end

Also note that the URL host needs to be set if using url in addition to path helpers (e.g. root_url and root_path):

Rails.application.routes.default_url_options[:host] = "www.example.com"

I would definitely prefer a non-monkey-patch solution or at least one where helpers could be included as needed depending on the controller of the action rendered. I'll wait to accept this to see if anyone can come up with such an answer.

OTHER TIPS

You can pass in a scope object with the scope parameter. So if you have access to an object with the helper included, like when in the view context, then you can pass that eg:

<%= Rabl::Renderer.json(object_to_render, 'api/v1/object/show', view_path: 'app/views', scope: self).html_safe%>

So outside of the view context you'd need to pass in a custom object with the helpers included to make this clean. eg

class RakeScope
  include FeedHelper
end

Rabl::Renderer.json(object_to_render, 'api/v1/object/show', view_path: 'app/views', scope: RakeScope.new() )

I've not tried the second option but the first works great.

While not quite the same problem, I had a similar problem accessing helpers from RSpec specs. I created a helper function that creates a scope that you can use to add whatever helpers you need. The following gave me access to the path and url helper methods and something similar should work for Rake.

#spec/support/rabl_helper.rb
def render_rabl(object, options={})
  options = {
    format:    'json',
    view_path: 'app/views',
    file:      example.example_group.top_level_description,
    scope:     RablScope.new
  }.merge(options)

  result = Rabl.render(object, options.delete(:file), options)
  options[:format] == 'json' ? JSON.parse(result) : result
end

class RablScope
  include Rails.application.routes.url_helpers
end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top