Rails Rendering a partial within JSON - ruby-on-rails

I am trying to render a partial inside a JSON file so that I can use it via AJAX. Currently in my JSON file I have:
<% self.formats = ["html"]%>
{
"html": "<%= raw escape_javascript(render(:partial => 'shared/mini_posts', :locals => {:type => "left"}).to_json )%>"
}
This currently returns no response, but my logs show that shared/mini_posts was rendered.
Note that if I try something like:
{
"html" : "test"
}
This returns correctly.
My jQuery looks like:
$j.ajax({
url('/thepage.json'),
dataType: 'json',
success: function(data){
console.log(data);
}
})

In my case, I had the same problem for about a day and a half and after trying lots of combinations of escape_javascript, to_json, render ... content_type, etc I finally achieved what I was looking for, that is rendering a HTML partial in a json response.
So in your controller you have an action like
def index
#candidatos = Candidatos::Base.paginate(page: params[:page], per_page: 3).to_a
respond_to do |format|
format.html # index.html.erb
format.json # index.json.erb
end
end
and if the request had a .json it will use the index.json.erb template, and in my case that template is something like
<% self.formats = ["html"] %>
{
"html":<%= thumbnails_tag(#candidatos).to_json.html_safe %>
}
Note the self.formats = ["html"] is necessary because otherwise the "view" won't find the partial because it will look for a .json partial. and more important, don't use escape_javascript because it will fill the html with \t and \n. In other words, the idea is to pass the output of your partial to .to_json and then to .html_safe.
thumbnails_tag is just a helper I created because I'm using the partial in lots of parts of the app, but basically it has something like
def thumbnails_tag objs
#Uncomment the line below to test when no much data available
# #listas.fill(#listas.first, 0..6)
thumb_span = 4
case #candidatos.length
when 1..3
thumb_span = 12 / #candidatos.length
else
thumb_span = 4
end
thumbs = {span: thumb_span}
render partial: 'candidatos/thumbnails', locals: {candidatos: #candidatos, thumbnail_options: thumbs }
end
Finally, and just as an example, with this approach, in your .js assets you can do something like:
$.get('http://localhost:3000/candidatos.json?page=2', function(d){}, 'json')
.success(function(d){
$('#presidentes div.row-fluid .thumbnails').parent().append(d.html);
})
.error(function(event,error){
console.log(error);
})
No need to gsub for \t and \n in your rails view or JSON.parse string in your Javascript.

You need to change your controller. In the respond_to part you need to add json rendering. Like this:
respond_to do |format|
format.json { render :json => #instancevar }
....
...
..
end
Then you can simply add .json to your url and you will receive the data formated as json. What you might need to do is disabeling the JSON root hich is automaticly added by default. Just add this line to your environment (development.rb, production.rb,...) configuration:
config.active_record.include_root_in_json = false
This is important when you are parsing the json.

You can't call to_json on a partial... it's a method of ActiveRecord. If you want json there, then it should be inside the partial.

Related

How does my ajax call know where my json is in rails

I have a javascript file with some ajax in it as follows.
$.ajax({
type: "GET",
contentType: "application/json; charset=utf-8",
url: 'data',
dataType: 'json',
success: function (data) {
draw(data);
},
error: function (result) {
error();
}
});
I also have created a method in a controller which renders json.
class GraphController < ApplicationController
def index
end
def data
render :json => User.select('value').map(&:value)
end
end
So my question is, how does rails know where the json is coming from especially as I'm not returning a physical file from my controller. What happens if I also have a physical .json file in my folder structure? Is there a heirarchy of how a view will look for a json file (eg physical file>jbuilder file>controller action)?
Every Action must render something.
Either you render something explicitly or rails will look for a page with name similar to the action in inside respective controller's folder in views.
You may render an html.erb, .json, .haml etc from views( provided you specify respond to format)
If you are rendering someting explicitly (which is true in your case, as json) Rails wont bother to look into views folder.
Or otherwise you may just skip render :json statement and specify that object in .json file, with respond to :json.
Here in your scenario, you are rendering a json object, which will be accepted in the success: section of the AJAX function's data arguement.
in ajax call.. contentType: "application/json; charset=utf-8", defines what is the type of request you are querying with rails.What that says is, "if the client wants HTML in response to this action, just respond as we would have before, but if the client wants XML, return them the list of people in XML format." (Rails determines the desired response format from the HTTP Accept header submitted by the client.).
Take a look respond_to api how rails responds to different types of request -js/xml/html/json
so you can try this in your controller as well..edit the data action like this and try..any call to data such as js/html/xml/json will work and rails will understand what type of response it needs to send.
def data
format.html { redirect_to(user_list_url) }
format.js
format.xml { render :xml => #users.to_xml(:include => #accounts) }
format.json {render :json => User.select('value').map(&:value) }
end
to render any error from controller to view..can be done like this:-
if #user.present?
format.json {render :json => User.select('value').map(&:value) }
else
format.js { render :json => #user.errors.full_messages.join(' '),
:status => 400 }
end
use this in view in ajax.error function like this
.error(function(data) {
$("#show_error").html("An Error Occurred,Please try again.");
});
HOPE THIS HELPS

Rails: How to choose which js file a controller action to render?

I know the fact that by default Rails chooses the javascript file depending on action's name to render:
For example if I have
def create
#Code and Stuff happening here
end
and here I have
create.js.erb
which will be ran by default
But is there a way that I can choose a different javascript file to be rendered from inside the action ?
For example
create1.js.erb
create2.js.erb
You'll want to add something like the following:
respond_to do |format|
format.js { render :create1 }
end
Alternately, if you had a different path to it besides the default you could use:
format.js { render :file => "/path/to/save.js.erb" }
If it is a more dynamic requirement than this, you could always use string interpolation or "string".to_sym to render the desired view.

is there a way to render form helpers dynamically via ajax?

The problem is:
I need to render a collection of checkboxes via ajax, so I have this:
$("#imovel_tipo_imovel_id").on "change", ->
$.get("/admin/caracteristicas", { tipo_imovel_id: $(this).val() })
When I change a select value, it will hit my controller and render back a collection of checkboxes. The problem is that the partial I need to render must be inside a form and sent back to a different controller.
= simple_nested_form_for #imovel do |f|
.caracteristicas
= render 'my_partial', f: f
the partial
= f.simple_fields_for :caracteristicas_imovel do |c|
= c.collection_check_boxes :caracteristica_id_in, #caracteristicas, :id, :descricao
the js.erb responde:
$(".caracteristicas").html("<%= render 'my_partial' %>")
The controller:
def index
respond_to do |format|
format.js { #caracteristicas = Caracteristica.where(tipo_imovel_id: params[:tipo_imovel_id]) }
end
end
You see? So when I try to render my partial via ajax it complains that it has no f variable.
Am I doing this right? Is there a better way?
I would just use actual html here. Try rendering this page with the full code, inspecting it, and just copy/pasting the rendered html into your partial. I'm sure there's a way to hack it with helpers, but it just seems easier this way.

Adding rendered HTML to JSON

Given a controller MapsController:
class MapsController < ApplicationController
def index
#campings = Camping.finm(:all) #in reality a much more complex scope.
respond_to do |format|
format.html
format.json { render :json => #campings }
end
end
end
This renders the JSON just fine. But now, I'd like to pass along some HTML to inject into the DOM:
$.ajax({
dataType: "json",
url: "maps.json?bounding=45.446465,-4.935988,53.944621,17.036668",
}).done(function (data) {
//...
var gInfoWindow = new google.maps.InfoWindow({
content: camping.infowindow
});
//...
$("#campings").append(camping.listing);
});
This JavaScript assumes a .listing and .infowindow attribute in each returned JSON-Object. They should contain HTML,
rendered with the partials campings/_infowindow.html.haml and campings/_listing.html.haml.
Is this the correct angle to tackle this? Or should I rather build the HTML within the JavaScript and avoid sending HTML? If so, is there still a way to use partials to build the actual HTML?
How can I add listing and infowindow to the ObjectsCamping model does not have these fields?
Maybe a bit rough (and not 100% super the "Rails way") but working fine for me in a similar situation:
render :text => {:result => "success",
:document_row => render_to_string(
:file => "admin/documents/_document_row",
:formats => "html",
:layout => false,
:locals => {:documentable => documentable})}.to_json
so roughly just generating a hash and use render_to_string to get the html from th _document_row template.
If you use something like KnockoutJS or another javascript data-binding or templating tool, you can have a skeleton 'template' in the page to start with, that gets filled in with camping listings when you make the ajax request.
The way it works is that you have your table or list or whatever of camping listings bound to an array of camping objects in your Knockout model. When you make your ajax request, you just update that array with the json that comes back. When that array is updated, the DOM is automatically updated to show the new listing. This lets your ajax request get the data only and not all the HTML markup, which means fewer bytes over the wire, and you can separate the act of fetching new data from updating the DOM based on that data.

Is there an easy way to use a JSON layout in Rails 3.1 for `render json: {}`?

Is it possible to specify a layout for rendering JSON in Rails 3.1+ (not that I found any easy way to do it in any previous version of Rails)?
I've been using a helper like this:
def render_as_json(obj, status = 200, *args)
render(inline: obj.to_json(*args), layout: 'default', status: status)
end
It doesn't seem like render json: obj will render a layout.
I just wanted to have some metadata in the layout file:
<%- #content = yield -%>
{
"data":<%= #content.present? ? raw(#content) : '{}' %>,
"metadata":<%= raw(json_layout_metadata.to_json) %>
}
I know this is old now but I was trying to use a JSON layout and an XML layout and while searching I found your question and it helped me somehow solve my problem so here is what I did for the JSON part and the XML is pretty much the same:
Create a template file in the layout folder in your application(in the same directory of application.html.erb), call it anything but make its extension ".json.erb", let's assume you named it "json_layout.json.erb". Put in it whatever constant content you want to add and in the place you want to display dynamic data put a
<%= yield %>
In my case, this is my template:
{"status": <%= response.status %>,"data": <%= yield %>}
Now in your controller where you want to display JSON use the following format in the respond_to block:
format.json { render :inline => #the_object.to_json(any_additional_options) , :layout => "json_layout.json.erb" }
Just be careful in case of XML to put in the options of the to_xml method
:skip_instruct => true
as you would probably don't need the full XML generated by default because you add your own in the layout.

Resources