5

I've got some fairly complex JSON responses in my application for my Ticket model and I'd like my TicketDecorator to be the one who builds those responses.

However, I've already setup and API for my system and use RABL to build those JSON responses, so I'd like to reuse the templates that I've already created.

I'm wondering if it's possible to render a RABL template from within a method inside TicketDecorator, something like this:

Here is my RABL template tickets/show.json.rabl

object @ticket

attributes :id, :link, :reported_ago_in_words_with_reporter,
           :last_updated_in_words_with_updater, :priority_label, :status,
           :location, :category_list

node(:attachment_urls) { |ticket| [ asset_path(ticket.first_attachment_url),     asset_path(ticket.second_attachment_url), asset_path(ticket.third_attachment_url) ] }

node(:comment_count) { |ticket| ticket.comments.count }

child :recent_comments do
  extends 'comments/index'
end

and here is my TicketDecorator method:

class TicketDecorator < ApplicationDecorator
  def as_json
    h.render(template: "tickets/show", formats: :json)
  end
end

However, this doesn't work because I can't sucessfully set @ticket, and I get an error saying: undefined method `first_attachment_url' for nil:NilClass because @ticket is nil.

Anybody have any good solutions on how I can make these two work nicely together?

My only real thought would be rendering the template to a string and using RABL manually, but I'm not sure how I'd be able to call render_to_string inside of Draper since its not a view helper.

Any thoughts about that?

user229044
  • 232,980
  • 40
  • 330
  • 338
TheDelChop
  • 7,938
  • 4
  • 48
  • 70

2 Answers2

1

If it is a matter of accessing objects in Rabl, maybe this can be of help to you.

Also on your custom nodes I would access the object directly, instead of relying on the block variable. The latter is imo meant for handling collections, like this:

collection @tickets
  attribute :name
  node(:some_complex_stuff) {|ticket| ticket.vendor.heavy_lifting}

You might also look into the fact, that you can call any object method like an attribute since it still is Ruby :)

class Ticket
  def we_got_what
    "the funk!"
  end
end

In order to get funky in your Rabl just do:

object @ticket
 attribute :we_got_what
Community
  • 1
  • 1
Benjamin
  • 1,726
  • 1
  • 14
  • 35
0

There's now a rabl wiki entry describing a situation like this. For others arriving, check it out here

The solution is to send the decorator to rabl rather than render rabl from the decorator. Flipping the responsibility makes things a bit easier.

Dane O'Connor
  • 75,180
  • 37
  • 119
  • 173