I have two rails applications that communicate together.
In the first application i have the following method in my controller:
def delivery_status envelope = Envelope.find(params[ : id]) render : json => envelope.to_json end
which, if go to the url in my browser, nicely shows my the JSON. Seems ok.
However, if i call this through jQuery, from my second application, using the following:
$(document).ready(function(){
$('.get_sms_details').live('click', function(event) {
var el = $(this),
data_url = el.attr('data-url');
$.ajax({
url: data_url,
dataType: 'text',
success: function(data, status, req) {
alert('received with status' + status)
alert('received json ' + data);
}
});
});
});
then the right url is hit with the correct parameters but data is always empty.
I first tried using $.getJSON, then $.get to end at $.ajax. I am not sure but it seemed i was doing something wrong at server-side.
The request looked fine inside firebug, but the response was always empty. Yet, i did not understand, if let the browser hit the same url, i got my json object.
So how do you solve this? Well, i was reading the documentation of $.ajax, and there i found:
When data is retrieved from remote servers (which is only possible using the
scriptorjsonpdata types), the operation is performed using ascripttag rather than an XMLHttpRequest object.
So, jsonp was the way, but how?
First, i changed my jQuery code:
$(document).ready(function(){
$('.get_sms_details').live('click', function(event) {
var el = $(this),
data_url = el.attr('data-url');
data_url = data_url
$.ajax({
url: data_url,
dataType: 'jsonp',
success: function(data) {
envelope = data.envelope;
alert('received envelope ' + data.envelope.id);
}
});
});
});
but then my server-side needed to be able to handle the jsonp.
I handled that using the following code:
def delivery_status
envelope = Envelope.find(params[ :id])
render_json envelope.to_json(:include => [: deliveries, : log_lines])
end
private
# render json, but also allow JSONP and handle that correctly
def render_json(json, options={})
callback, variable = params[:callback], params[:variable]
logger.debug("render json or jsonp? Callback = #{callback}, Variable=#{variable}")
response = begin
if callback && variable
"var #{variable} = #{json};\n#{callback}(#{variable});"
elsif variable
"var #{variable} = #{json}"
elsif callback
"#{callback}(#{json});"
else
json
end
end
render({:content_type => :js, :text => response}.merge(options))
end
Where the render_json does all the dirty work for me :)
I was somewhat expecting this to be standard inside rails3, and as Kevin Chiu pointed out in the comments, it is and much simpler at that:
def delivery_status
envelope = Envelope.find(params[ :id])
render :json => envelope.to_json(:include => [: deliveries, : log_lines]), :callback => params[:callback]
end
Awesome :)
