Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Render Rabl templates from view (in order to bootstrap a backbone.js model) #42

Closed
scottmessinger opened this issue Jun 15, 2011 · 47 comments

Comments

@scottmessinger
Copy link

In the backbone.js FAQ, Jeremy suggests bootstrapping a backbone.js model by using ERB and converting the object/collection to json:

<script>
  Accounts.refresh(<%= @accounts.to_json %>);
  Projects.refresh(<%= @projects.to_json(:collaborators => true) %>);
</script>

http://documentcloud.github.com/backbone/#FAQ-bootstrap

How could I render a rabl template in the view instead of calling to_json on the object/collection?

@spoptchev
Copy link

Just render the rabl template:

<%= render(:file => 'path_to_rabl_template.json.rabl') %>

@scottmessinger
Copy link
Author

Awesome! That's super helpful!

On Fri, Jul 1, 2011 at 9:04 AM, spoptchev <
reply@reply.github.com>wrote:

Just render the rabl template:

<%= render(:file => 'path_to_rabl_template.json.rabl') %>

Reply to this email directly or view it on GitHub:
#42 (comment)

@nesquena
Copy link
Owner

nesquena commented Jul 8, 2011

@scottmessinger Can you confirm this works and if you have run into any other issues? I believe this is how I am doing it in my backbone project as well. Perhaps there should be a guide on the RABL wiki combining backbone and RABL.

@brentmurphy
Copy link
Contributor

Is it also possible to set instance variables for the partial to access using this technique (e.g. for object/collection). Cheers.

@mschulkind
Copy link
Contributor

It seems like you probably need a way to set the object, perhaps with the :object option to render. I'm trying to do this as well, but instead I'm trying to embed the JSON version of object A inside the HTML version of object B. There doesn't appear to be a clean way to do this right now. I think the partial() function in RABL is almost exactly what is needed here.

@nesquena
Copy link
Owner

Yeah, still trying to figure out the best way to expose this functionality in RABL...

@mschulkind
Copy link
Contributor

To answer my own question somewhat, this works:

  1. Create a partial for the object, this has to be named "app/views/model/_foo.json.rabl", note the leading underscore to indicate a partial.
  2. In your HTML view: render('model/foo.json.rabl', object: foo_object)

This is not as clean as it could be, but this is 99% of the way there and it works.

@nesquena
Copy link
Owner

Interesting, that isn't necessarily a bad approach. Thanks for spelling that out. Added that post and a link back to here to the Backbone Integration wiki page as a placeholder. I'd love to flesh out this guide more in the future.

@mschulkind
Copy link
Contributor

Well, I see two possibly cleanups:

  1. RABL partial support should enforce the leading underscore to make this less confusing.
  2. It'd be nice if the line could be something more like "render(foo_object, :format => :json) " or even "render(json: foo_object)"

I'm not sure if #2 is possible without Rails changes though.

@nesquena
Copy link
Owner

  1. I like RABL supporting partials without underscores because I want to re-use templates I am using in other places as a regular templates
  2. Pretty sure this can't be done without messing around in Rails rendering

I am closing this for now because the solution you proposed is good enough

@scottmessinger
Copy link
Author

Thanks for all the help with this!

@raine
Copy link

raine commented Aug 5, 2011

Making the rabl file a partial breaks default functionality.

This seems to be the only way around it:

format.json {
  render('lolcats/_index.json.rabl', :object => @cats)
}

@mschulkind
Copy link
Contributor

I'm confused what you're suggesting here.

Your format.json suggests that you're calling this in a controller. Partials are meant for use from views, not controllers.

@raine
Copy link

raine commented Aug 5, 2011

Exactly, and if I make the rabl file a partial, I can't use the same file for both backbone and controller without this hack.

@mschulkind
Copy link
Contributor

But this is precisely what partials are for. How is this any different from how html views work? It just so happens with JSON/RABL, unlike with HTML, that a partial can look just like a full view for the same object, but that doesn't mean the abstractions should be any different.

If you want to have a JSON/RABL partial that can be embedded in other views, you create a partial.
If you happen to also want a view that is nothing more than exactly what is in that partial, then just render the partial in that view.

@willrjmarshall
Copy link

Hey,

When I try to do this, the best I can achieve is having "#<Rabl::Engine:0x007fad09cc7320>" rendered into my view.

Is there a way around this?

@mschulkind
Copy link
Contributor

example?

@nesquena
Copy link
Owner

When you try what specifically? can you gist it?

@willrjmarshall
Copy link

If I try this: https://gist.github.com/1297264

I get this: https://gist.github.com/1297266

Looks like to_s being called on the Rabl instance itself.

@mschulkind
Copy link
Contributor

What does the rabl file look like? What's it named?

@willrjmarshall
Copy link

rabl file is plates/_index.json.rabl

It looks like this: https://gist.github.com/1297270

@willrjmarshall
Copy link

(I've tried switching object to plates as I plan to do eventually, but it doesn't seem to be getting far enough to choke on that)

@mschulkind
Copy link
Contributor

What are you expecting to happen here?

You're passing in a collection of strings, but then expecting them to have attributes.

@willrjmarshall
Copy link

I'm expecting it to barf when it sees stuff it can't render.

I've also tried passing in a valid object that can render (when I access this through a controller method), but I get the same "#Rabl::Engine:0x007fad0d4d0500" issue when I render inline.

As far as I can tell, it's not trying to render the .rabl template at all.

@mschulkind
Copy link
Contributor

It's possible the collection part is breaking here, I have code almost identical to this that works, but for some reason I'm doing map{ render(...) }.join(','). Possibly I ran into the same problem.

@nesquena
Copy link
Owner

Interesting, are you on Rails 3.1? Looks like a bug but not sure how to fix it. I remember trying this before and having it work alright in Rails 2.3.

@mschulkind
Copy link
Contributor

Works for me on Rails 3.

On Tue, Oct 18, 2011 at 9:42 PM, Nathan Esquenazi <
reply@reply.github.com>wrote:

Interesting, are you on Rails 3.1? Looks like a bug but not sure how to fix
it. I remember trying this before and having it work alright in Rails 2.3.

Reply to this email directly or view it on GitHub:
#42 (comment)

@willrjmarshall
Copy link

I am on Rails 3.1, which might be the problem.

@mschulkind: even if I empty the .rabl partial the same thing happens, so I don't think it's getting far enough for that to be an issue.

@nesquena
Copy link
Owner

I know they changed the way rendering works on 3.1 but I don't know how and I don't actually have any 3.1 projects. Just Padrino, Rails 2.3 and Rails 3. So if anyone can help investigate and fix this in a patch, I'd appreciate it.

@mschulkind
Copy link
Contributor

I agree with nesquena, it looks like the template handler wiring isn't quite right, which definitely points to some sort of Rails change.

@mschulkind
Copy link
Contributor

@mschulkind
Copy link
Contributor

stevegraham/twilio-rb#12

...and another just for reference.

@nesquena
Copy link
Owner

Ah...yes that is extremely relevant. Thanks for tracking that down, looks like they changed the template handler api completely...

@willrjmarshall
Copy link

Is there likely to be a workaround for now?

@willrjmarshall
Copy link

I'm looking into a patch for this currently. Need the fix anyway :)

@nesquena
Copy link
Owner

I think the only way forward is to basically either take the haml approach (and try to make one handler for 3/3.1) or split it up in https://github.com/nesquena/rabl/blob/master/lib/rabl/template.rb even further creating a separate handler for 3.1 following stevegraham/twilio-rb#12 example

@willrjmarshall
Copy link

Ok, I've made some progress on this:

It's nothing to do with the HAML bug. The problem is that render() in Engine is getting "html" in self.request_format... when it should be "json". A temporary fix looks like this: https://gist.github.com/1297460

Check out line 17 - if we manually force the format to "json" this works as expected.

In the Rails 2 version, the format is being set using

{ :format => #{template.format.inspect} }

format is a private method on ActionView::Template in Rails 3, so we can't do this anymore.

Thoughts?

@willrjmarshall
Copy link

Ok, to be ultra-specific, something has changed between Rails 3.0 and Rails 3.1 to make this start returning "html"

    def request_format
      format = self.request_params.has_key?(:format) ? @_scope.params[:format] : nil
      if request = @_scope.respond_to?(:request) && @_scope.request
        format ||= request.format.to_sym.to_s if request.respond_to?(:format)
      end
      format && self.respond_to?("to_#{format}") ? format : "json"
    end

It's getting "html" from

"request.format.to_sym.to_s" 

but the same thing doesn't occur in the Rails 3.0 test-case. Hmmm.....

@willrjmarshall
Copy link

#126

@mattiassvedhem
Copy link

I've been trying to do as stated in the Wiki under Backbone integration but I can't get the view to render correctly:

render('restaurants/show', formats: :json, object: Restaurant.first)

I've tried to name the template _show.json.rabl show.json.rabl show.json.rabl show.rabl
but without success, I did get this to work:

render('show.json.rabl', object: restaurant).html_safe

But only in another view in the restaurants folder and I need to explictly do show.json.rabl

I'm using Rails 3.2 and Rabl 0.7.0, is there any recent changes on this? is the recommended way to use Rabl::Renderer in views also?

Edit: Oh and as suggested in #126
I've also tried:

render(file: 'restaurants/show', object: Restaurant.first, formats: :json).html_safe

All I get is

ActionView::MissingTemplate: Missing template restaurants/show with {:locale=>[:sv_SE], :formats=>[:json], :handlers=>[:erb, :builder, :coffee, :haml, :rabl, :eco]}. Searched in:

@mschulkind
Copy link
Contributor

Looks like there's relevant discussion going on at #126.

@mattiassvedhem
Copy link

Yes, I've tried the suggested methods there, but can't get it to work, only with this, and only if already in a template of the same folder:

render('show.json.rabl', object: restaurant).html_safe

I also need to name the file _show.json.rabl in order for this to work.

@mschulkind
Copy link
Contributor

This has been my experience as well since well before rails 3.1 even.

On Mon, Jul 30, 2012 at 12:08 PM, yeggeps <
reply@reply.github.com

wrote:

Yes, I've tried the suggested methods there, but can't get it to work,
only with this, and only if already in a template of the same folder:

render('show.json.rabl', object: restaurant).html_safe

I also need to name the file _show.json.rabl in order for this to
work.


Reply to this email directly or view it on GitHub:
#42 (comment)

@nesquena
Copy link
Owner

Yeah, sorry this inline rendering stuff is so troublesome. Seems that what you need to do has changed on several occasions even just between Rails 3 and 3.1. If anyone can help update the wiki with the most relevant info, I'd appreciate it. Or if there's a simple way we can improve the template handler registration so this is less painful in the future.

@nesquena
Copy link
Owner

As you mentioned there's usually a way to pull it off. You can also Rabl.render as you suggested which would be a simpler way to render inline templates if all else fails.

@mattiassvedhem
Copy link

So if using Rabl::Renderer or Rabl.render, is there a way to set the default view_path so I don't have to specify it every time?

@mattiassvedhem
Copy link

According to the readme on view_paths

If view_paths is set to a path, this view path will be checked for every rabl template within your application. Add to this
path especially when including Rabl in an engine and using view paths within a another Rails app.

it implies that you don't have to explicitly set config.view_paths = ['app/views'] when using Rabl in a normal Rails app, is this correct? It's empty by default so I guess it needs to always be set?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants