10

I am trying to have a json response in which some value is html rendered by a partial

#projects_Controller.rb

def index
  respond_to do |f|
    f.json 
  end
end

# index.json.erb

  {
     "html":"<%= raw escape_javascript(render :partial => 'projects/disclaimer') %>"
  }

But I get the following error:

  ActionView::Template::Error (Missing partial projects/disclaimer with {:handlers=>[:erb, :rjs, :builder, :rhtml, :rxml], :formats=>
  [:json], :locale=>[:en, :en]} in view paths "c:/rails/app/views", "c:/rails/vendor/plugins/more/app/views", "C:/Ruby192/lib/ruby/gems/1.9.1/gems/devise-1.1.8/app/views")

It appears JSON requests renders partial with .json.erb in its name but not .html.erb, which is what I have. Is there a way for me to specify 'html'.

ADDED: If the request is 'js', and in index.js.erb I render the almost same code: # index.js.erb

  disclaimer = {
     "html":"<%= raw escape_javascript(render :partial => 'projects/disclaimer') %>"
  }

it does find the projects/disclaimer.html.erb and renders it correctly. I wonder why is there such an inconsistency in that if one requested js, any partial rendering in its template will look for partial_name.html.erb but if one requested json, the partial rendering would ask for partial_name.json.erb?

Thank you

Nik So
  • 16,683
  • 21
  • 74
  • 108

4 Answers4

13

Got it: All one needs is this line in the .json.erb file <% self.formats = ["html"] %>

So the full index.json.erb

      <% self.formats = ["html"] %>
      disclaimer = {
        "html":"<%= raw escape_javascript(render :partial => 'projects/disclaimer',
                    :content_type => 'text/html'), 
                    :locals => {:localVariable => @localVariable} 
                %>"
      }
Nik So
  • 16,683
  • 21
  • 74
  • 108
  • 5
    This approach also works from inside a controller that's rendering JSON; I set `self.formats = [:html]`, then `render_to_string(:partial=>'an_html_partial', :locals=>{:whatever=>whatever})`, and then I can render json fine. – alxndr Mar 06 '12 at 19:52
  • In case you also have other json partials, you might want to do `self.formats += [:html]` instead. – Tero Tilus Jan 31 '14 at 08:59
5

My answer is similar to Nik's above. I have the following helper for json.erb templates:

# helpers useful for json.erb templates
module JsonHelper

  # Same as render but force actionview to look for html templates instead of json.
  def render_html(options={}, locals={}, &block)
    old_formats = formats
    self.formats = [:html] # hack so partials resolve with html not json format
    render options, locals, &block  

  ensure
    self.formats = old_formats 
  end 

  # json escape a string. For example <%=json "some { string }" %>
  def json(value)
    raw value.to_json
  end 
end

So now I can write templates like

{
  "html": <%=json render_html(:partial => 'some_partial') %>,
  "status": success
}

This would be nicer if actionview allowed rendering with a content_type like in 23tux's example (which doesn't work for me). It would also be nicer if only *.html.erb underwent html escaping instead of all *.erb files.

ajh
  • 121
  • 2
2

For future readers, you may pass on formats parameter like this.

= render partial: 'user', locals: {xyz: @xyz}, :formats => [:html]
Nadeem Yasin
  • 4,493
  • 3
  • 32
  • 41
0

I'm not sure if I got you right, but maybe you can play with the content type like this:

disclaimer = {
  "html":"<%= raw escape_javascript(render :partial => 'projects/disclaimer', :content_type => 'text/html'), :locals => {:localVariable => @localVariable} %>"
}

The :locals is just if you want to pass an var to the partial.

23tux
  • 14,104
  • 15
  • 88
  • 187
  • No no, I think you're right on the money: rails is asked to serve json, so anything that it serves, including any renders will have to be json not html.erb. so when I ask for a partial.html.erb inside the response, it throws an error saying that partial.JSON.erb not found. Strange thing is, if I ask for .js (JSONP?) in header, which means rails should serve all partials in .js.erb ending, but this time, it wouldn't mind serving .html.erb and won't say it's not found. That's an inconsistency in my opinon.... But after adding the :content_type => 'text/html', it still throws that same error – Nik So Mar 23 '11 at 08:57