views:

5495

answers:

5

I'm trying to generate a JSON response that includes some HTML. Thus, I have /app/views/foo/bar.json.erb:

{
  someKey: 'some value',
  someHTML: "<%= h render(:partial => '/foo/baz') -%>"
}

I want it to render /app/views/foo/_baz.html.erb, but it will only render /app/views/foo/_baz.json.erb. Passing :format => 'html' doesn't help.

+2  A: 

You have two options:

1) use render :file => "foo/_baz.json.erb"

2) change template format to html by setting @template_format variable

<% @template_format = "html" %>
<%= h render(:partial => '/foo/baz') %>
roninek
+6  A: 

Building on roninek's response, I've found the best solution to be the following:

in /app/helpers/application.rb:

def with_format(format, &block)
  old_format = @template_format
  @template_format = format
  result = block.call
  @template_format = old_format
  return result
end

In /app/views/foo/bar.json:

<% with_format('html') do %>
  <%= h render(:partial => '/foo/baz') %>
<% end %>

An alternate solution would be to redefine render to accept a :format parameter.

I couldn't get render :file to work with locals and without some path wonkiness.

James A. Rosen
too hackish for my tastes. Better to specify the entire extension.
Tim Harper
+8  A: 

What's wrong with

render :partial => '/foo/baz.html.erb'

? I just tried this to render an HTML ERB partial from inside an Atom builder template and it worked fine. No messing around with global variables required (yeah, I know they have "@" in front of them, but that's what they are).

Your with_format &block approach is cool though, and has the advantage that you only specify the format, whereas the simple approach specifies the template engine (ERB/builder/etc) as well.

Sam Stokes
This is really the most straightforward approach, and works seamlessly for me.
Derek P.
The only downside to this is that if your partial renders other partials it'll fail unless you go in and change all your render partial calls to include the ".html.erb" on their name.
chrisrbailey
+1 for sure, but having to specify the template engine, combined with the concern chrisbailey raises about nested partials makes me wary.
James A. Rosen
you don't have to specify the templating engine for this to work. (At least as of rails 3). The following works just fine: render(:partial => "baz.html")
Tim Harper
'/foo/bar.html' works too!
Cheng
A: 

I came across this thread when I was trying to render an XML partial in another xml.builder view file. Following is a nice way to do it

xml.items :type => "array" do
    @items.each do |item|
        xml << render(:partial => 'shared/partial.xml.builder', :locals => { :item => item })
    end
end

And yeah... Full file name works here as well...

Shikher
This suffers from the same inner-partials-problem that @chrisrbailey mentioned on another answer: if the partial you call with a full filename itself uses partials (without specifying the full file name for each), it will fail.
James A. Rosen
+1  A: 

For Rails 3, the with_format block works, but it's a little different:

  def with_format(format, &block)
    old_formats = formats
    self.formats = [format]
    block.call
    self.formats = old_formats
    nil
  end
zgchurch