How do I render a partial of a different format in Rails?

Ruby on-RailsFormatRenderPartialActionview

Ruby on-Rails Problem Overview


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.

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

Beginning with Rails 3.2.3, when calling render :partial (only works outside of the respond_to block).

render formats: [ :html ]

instead of

render format: 'html'

Solution 2 - Ruby on-Rails

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.

Solution 3 - Ruby on-Rails

Rails 4 will allow you to pass a formats parameter. So you can do

render(:partial => 'form', :formats => [:html])} 

Note you can do something similar in Rails 3 but it wouldn't pass that format to any sub partials (if form calls other partials).

You can have the Rails 4 ability in Rails 3 by creating config/initializers/renderer.rb:

class ActionView::PartialRenderer
  private
  def setup_with_formats(context, options, block)
    formats = Array(options[:formats])
    @lookup_context.formats = formats | @lookup_context.formats
    setup_without_formats(context, options, block)
  end

  alias_method_chain :setup, :formats
end

See http://railsguides.net/2012/08/29/rails3-does-not-render-partial-for-specific-format/

Solution 4 - Ruby on-Rails

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

Solution 5 - Ruby on-Rails

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.

Solution 6 - Ruby on-Rails

In Rails 3, the View has a formats array, which means you can set it to look for [:mobile, :html]. Setting that will default to looking for :mobile templates, but fall back to :html templates. The effects of setting this will cascade down into inner partials.

The best, but still flawed way, that I could find to set this was to put this line at the top of each full mobile template (but not partials).

<% self.formats = [:mobile, :html] %>

The flaw is that you have to add that line to multiple templates. If anyone knows a way to set this once, from application_controller.rb, I'd love to know it. Unfortunately, it doesn't work to add that line to your mobile layout, because the templates are rendered before the layout.

Solution 7 - Ruby on-Rails

Just elaborating on what zgchurch wrote:

  • taking exceptions into account
  • returning the result of the called block

Thought it might be useful.

def with_format(format, &block)
  old_formats = formats
  begin
    self.formats = [format]
    return block.call
  ensure
    self.formats = old_formats
  end
end

Solution 8 - Ruby on-Rails

You have two options:

  1. use render :file

    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') %>

Solution 9 - Ruby on-Rails

I had a file named 'api/item.rabl' and I wanted to render it from an HTML view so I had to use:

render file: 'api/item', formats: [:json]

(file because the file have no underscore in the name, formats and not format (and passes and array))

Solution 10 - Ruby on-Rails

It seems that passing a formats option will render it properly in newer Rails version, at least 3.2:

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

Solution 11 - Ruby on-Rails

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...

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJames A. RosenView Question on Stackoverflow
Solution 1 - Ruby on-RailsTim HainesView Answer on Stackoverflow
Solution 2 - Ruby on-RailsSam StokesView Answer on Stackoverflow
Solution 3 - Ruby on-RailsDrewBView Answer on Stackoverflow
Solution 4 - Ruby on-RailszgchurchView Answer on Stackoverflow
Solution 5 - Ruby on-RailsJames A. RosenView Answer on Stackoverflow
Solution 6 - Ruby on-RailsTony StubblebineView Answer on Stackoverflow
Solution 7 - Ruby on-RailsvipheView Answer on Stackoverflow
Solution 8 - Ruby on-RailsroninekView Answer on Stackoverflow
Solution 9 - Ruby on-RailsDorianView Answer on Stackoverflow
Solution 10 - Ruby on-RailsMario UherView Answer on Stackoverflow
Solution 11 - Ruby on-RailsGarfieldView Answer on Stackoverflow