How does my ajax call know where my json is in rails - ruby-on-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

Related

Rails - AJAX window.location redirect not working

In my Rails app, stringified JSON form input is passed to a controller via AJAX - on success, the user is to be redirected to a summary page, but the AJAX redirect doesn't seem to be working...
$.ajax({
url: "report/submission",
type: "POST",
beforeSend: function(xhr) {xhr.setRequestHeader("X-CSRF-Token", $("meta[name='csrf-token']").attr("content"))},
data: {"report" : reportParameter},
success: function(response) {
window.location.href = "/report/summary";
}
});
and the associated controller
def submission
#incomingReport = ActiveSupport::JSON.decode(params[:report])
#newReportIDArray = Array.new
#incomingReport.each do |x|
hash = ActionController::Parameters.new(x)
#new_report = Report.new(report_params(hash))
#new_report.save
end
end
Everything else seems to work just fine - the data is entered, but the redirect does not trigger. I've searched all around and it looks like this is the syntax that everyone says to use, but it doesn't seem to work for me. I'm sure that I am doing something wrong, but I'm not sure what.
Editing to clarify problem/solution
During a chat with #Jonathan and #Kumar, I noted that window.open("/report/summary") did work correctly - #Jonathan suggested that I just try console.log(window.location) before the ajax call, and to my surprise, the script from a function from elsewhere in my app was logged. Big shocker now - THE FUNCTION WAS CALLED location()!!! Renaming the function and then restarting the app in a new window solved the problem. Learn from my mistake, kids - don't name a function location().
Ruby isn't my first language but it doesn't look like you're sending a response back. Try returning something or putsing. Look up how to do that with rails, a proper response. Maybe render json: [success: 200] or something like that. Maybe it's irrelevant. In any case, if it's not working try changing success for complete and log out the response to debug. The complete will always fire, but success won't always.
Try this:
respond_to do |format|
format.json do
render json: {
success: 200
}.to_json
end
end
In your AJAX setup, add "datatype": "json".
You could improve the response to conditionally send a failure like success: 500 if something went wrong.
You don't really need respond_to block here because you're always expecting JSON, but that's the kind of format that's often used in Rails if not mistaken.
If that doesn't work just use the render json: part as that is definitely a return.
Update
Further from our discussion it turns out that after making a robust Ajax call and tweaking the action, the final hurdle was a window.location that was not working. The cause of the problem was that location had been rebound to another function. All that needed to be done in the end is to rename that custom function and Bob's your uncle.
Add a datatype
$.ajax({
url: "report/submission",
type: "POST",
dataType: 'json', #Add json data type, as we'll render json from controller
beforeSend: function(xhr) {xhr.setRequestHeader("X-CSRF-Token", $("meta[name='csrf-token']").attr("content"))},
data: {"report" : reportParameter},
success: function(response) {
console.log("Response is ", response);
//When we get 200, this function should execute
window.location.href = "/report/summary";
},
error: function(error){
console.log("Error is ", error);
}
});
And in the controller
def submission
#incomingReport = ActiveSupport::JSON.decode(params[:report])
#newReportIDArray = Array.new
#incomingReport.each do |x|
hash = ActionController::Parameters.new(x)
#new_report = Report.new(report_params(hash))
#new_report.save
end
respond_to do |format|
format.json { head :ok } #This will return 200 status back to ajax call
end
end

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.

Rails Rendering a partial within JSON

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.

How to access Jquery's Ajax call in RoR?

Guys I'm really novice to this RoR, and at this moment i reached to complex situation that "how to use Jquery's ajax() call in RoR?"
I've a controller called Projects like this
class ProjectsController < ApplicationController
def stagemilestone
#milestones=Milestone.find_by_sql("SELECT name, created_at FROM milestones WHERE stage=1")
end
end
and i want to call this action from jquery's ajax call and return the data, for this I'm using like this
$.ajax({
url: "/projects/stagemilestone",
success: function(){
//here i need the returned data from controller
// means output of #milestones
}
});
So please help me, how to do this?
Guys finally i found Solution as Follows and working Great!!
Controller
def stagemilestone
#milestones=Milestone.find(:all, :conditions => ["status_id=? and project_id=?",params[:stageid], params[:id]])
respond_to do |format|
format.html # index.html.erb
format.json { render :json => #milestones}
end
end
and My char.js looks like this
$.ajax({
type : 'get',
url : "/projects/stagemilestone",
data : "stageid=" + $(this).attr('name') + "&id=" + $.cookie('projectid'),
dataType : 'json',
async : false,
context : document.body,
success : function(response) {
}
});
I think what you want is to use "respond_to"
like this
class ProjectsController < ApplicationController
def stagemilestone
#milestones=Milestone.find_by_sql("SELECT name, created_at FROM milestones WHERE stage=1")
respond_to do |format|
format.js {render :json => #milestones}
end
end
end
Here's more info on respond_to, http://apidock.com/rails/ActionController/MimeResponds/InstanceMethods/respond_to
UPDATE: you may want to double check the accept's header of your ajax request (you can look at the request in firebug), you may need to use format.json. Refer here for the full list of MIME types and just make sure they match up:
http://apidock.com/rails/Mime
Add a parameter to your success callback; that will contain the response value.
success: function(response)
{
// response will be the HTTP / JSON / text returned from your controller
}
Just add a parameter to the callback function, like:
$.ajax({
url: "/projects/stagemilestone",
success: function(output){
//Do something with 'output'
}
});

Calling Rails update Method via Inline Edit

I was putting together a quick inline editing feature in my first Rails app and just as I was getting it working it occurred to me that I may be violating RESTful principles. The edit updated an image name. To do so, it submits, via PUT to Image#update and passes the new modified name as image[name].
The database gets updated properly, but I need that value back so that my markup can reflect the name change. To do that, I was calling /images/:id.json, but that got me wondering whether a PUT request can "validly" (in that RESTful sort of way) return a value like this.
Thoughts?
Update: For whatever it's worth, I'm using jQuery and the jEditable plugin to do the inline editing. Here's my jEditable code:
$(document).ready( function() {
$('h2').editable(
'/images/' + $('#image-id').val() + '.json',
{
method: 'PUT',
name: 'image[name]',
submitdata: { authenticity_token: $('#auth-token').val() },
submit: 'Save',
cancel: 'Cancel'
}
);
})
And my Image#update method as it exists right now:
def update
#image = Image.find( params[:id] )
if #image.update_attributes( params[:image] )
flash[:notice] = "Successfully updated image."
respond_to do |format|
format.html { redirect_to #image }
format.json { render :json => #image.to_json }
end
else
render :action => 'edit'
end
end
If your concern is just that your update method with JSON provide a response body and not just a 200 OK (Rails's head :ok) then I don't think you need to be worried. The default response is 200 OK so the only difference between what you're doing and what Rails does by default (in its scaffolds) is that you're also including a response body. As far as I can tell proper REST etiquette only requires that you return a 200 OK and doesn't care about the response body, which is in line with what you're doing.
Beyond that all your code looks excellent.

Resources