(Rails version 5.1.2)
I would like to respond to AJAX with HTML rather than javascript for much the same reasons as outlined in this stack overflow question.
However, I can't actually get it to work.
I'm using form_for with remote: true to send the request via AJAX. Note that I've also experimented with data: {type: :html}.
My controller action has the line render layout: !request.xhr? and has an associated view. It's this view that I want sent back to the client.
Yet the client-side code:
$("form").on('ajax:success', (e, data, status, xhr) ->
console.log xhr.responseText #using console.log data produces same result
)
Gives:
Turbolinks.clearCache()
Turbolinks.visit("http://localhost:3000/...", {"action":"replace"})
Where's the HTML?
Unless I am completely misunderstanding what you want to do, this should be what you are looking for:
Javascript:
$.ajax({
// remember to add this route to your routes file
url: "products/ajax_render",
success: function(data){
$('.some_div').html(data['html'])
},
});
Ruby on Rails:
def ajax_render
# render some view and store it in a variable
html = render "products/your_view"
# return it inside the json response
render json: { html: html }
end
Am I missing something?
Related
I'm wanting to send a post request from my JavaScript code to my show action in Ruby on Rails which contains data that I want to store in an instance variable so I can save it on a form in my view and upload it to my server.
As you can see below, the parameter 'base64' is showing up in my rails logs, but when I try to call #base64 in my view, after grabbing the value in the controller, it's nil.
Any advice is appreciated, thanks!
View
var full_base64 = "data:image/jpeg;base64," + base64;
$.ajax({
data: 'base64=' + full_base64,
type: 'POST',
url: "/videos/show/<%=#video.id%>"
});
Controller
def show
#video = Video.find(params[:id])
if params[:base64].present?
#base64 = params[:base64]
end
end
Routes
post 'videos/show/:id', to: 'videos#show'
Rails server log:
Started POST "/videos/show/1" for 127.0.0.1 at 2020-01-22 12:59:40 -0600
Processing by VideosController#show as */*
Parameters: {"base64"=>"data:image/jpeg;base64,iV...
...
, "id"=>"1"}
Console
>>
#base64
=> nil
>>
If I understand correctly you are trying to pass AJAX to the show action in your controller. This is a very GENERALIZED answer as you have failed to include any of your HTML code and it looks like you don't have a button to fire the AJAX. But I'll try to point you in the right direction. You need to do something along the general lines of:
var full_base64 = "data:image/jpeg;base64," + base64;
$.ajax({
data: 'base64=' + full_base64,
type: 'POST',
url: "/videos/my_ajax_upload"
});
That will send your AJAX call to a controller method I've called my_ajax_upload but you can call it whatever you like. In your controller you would need something like:
def my_ajax_upload
#video.update(base_64: params[:base64])
respond_to do |format|
format.js {render :action => "base_64_response" }
end
end
This responds to the initial AJAX call by saving the param you sent to the DB and replying by calling a file called base_64_response.js.erb which might look something like:
$('#pic_upload').html('<%= escape_javascript(render :partial => 'base_64_response') %>');
Which will render the HTML file called base_64_response.html.erb which needs to contain the html code you want to appear in the page that called it.
<div id="pic_upload">
<%= #base64 =>
</div>
The cycle is load page -> do something to trigger AJAX call to controller method -> process AJAX call with controller method -> render JS file -> JS file replaces div in page with new html
You probably need to read up more on how AJAX works in Rails. This RailsCast might help http://railscasts.com/episodes/136-jquery-ajax-revised?view=asciicast
Just FYI - I have also noticed strange things in Rails if you do not explicitly define the content type. In your posted example you are not stating the contentType and it could be parsing nil for that reason. When posting base 64 data you can specify the content type as:
$.ajax({
data: 'base64=' + full_base64,
type: 'POST',
contentType: 'application/octet-stream'
url: "/videos/show/<%=#video.id%>"
});
and it may change what the controller parses for the body.
How to post an image in base64 encoding via .ajax?
Just use string instead of symbol for hash key
if params["base64"].present?
#base64 = params["base64"]
end
How can I in Rails write a Coffeescript function to update a database column? I guess an Ajax call of sorts would be ideal:
id = $('#document').attr('data-document-id')
$.ajax
url: "/documents/#{id}/update_attr"
type: "GET"
success: (data) ->
console.log(data)
Is something like this the only way? Or is there something better?
Well, keep in mind that frontend code (html, css, js) cannot access the database directly. So you need an AJAX request.
REST best practices would require you to use a POST/PUT/PATCH method instead of the GET method which should never change the state of the application.
Also, you are not passing any value to the Rails backend.
$.ajax
url: "/whatever/#{id}"
type 'POST'
data:
key: value
success: (data)->
console.log data
On the Rails side you need to setup the appropriate route in config/routes.rb:
post '/whatever/:id', to: 'some_controller#some_action'
Still ideally, following the best practices, you probably have some sort of
resources :apples
already mapped to an ApplesController. You now have to implement the action, which will be like this:
def update
#object = Whatever.find(params[:id])
if #object.update(key: params[:key]
render json: { success: 1 }
else
render json: { success: 0 }
end
end
That implementation is not complete (it does not handle HTML requests, multi-key updates and other fancy things), but still it should solve your problem.
I have a page with a list of user sites and on it I am making an API call to check the status of something for each site. The problem is that it makes the page take forever to load, so I would like the page to load and then that table element to update after it's done checking using AJAX or jQuery. I'm not great with AJAX or jQuery though and all the Rails/Ajax tutorials I've been reading seem to deal more with forms and data stored within the database. Here's my table element:
Part of My View
<td>
<% if HTTParty.get(site.domain + 'api')["status"] == "ok" %>
OK
<% else %>
Error
<% end %>
</td>
The Controller Action Loading View
def sites_page
#sites = Site.where(user_id: current_user.id)
render 'sites_page'
end
How can I make this load separately as mentioned above? I know I don't have any attempted code yet, but I really don't know where to start.
Thanks for your help.
Just attach AJAX call to the td on window load, it will be evaluated later after page is rendered. AJAX call can be something like this:
$(window).load(function() {
var target = $(".td-that-will-be-evauated-later")
url = target.data("url")
$.ajax({
url: url,
type: "GET",
dataType: "json",
success: function(result){
target.html(result.body)
},
error: function(xhr, status, error) {
$(target).html("error");
}
})
})
Url should point to the controller action that will fetch information for particular user, for example:
class UsersController < ActionController::Base
def fetch_info
#user = User.find(params[:id])
#response = #user.fetch_info
render json: {success: true, body: response.body}
end
end
I want to perform an action do file in controllers/static_pages_controller.rb:
def fileopen
my_file = File.new("public/CHNAME1.txt","w")
my_file.write "\tfasf"
my_file.close
end
(it work well when i define it in helper and call it in view.)
in myview.html.erb, i want some thing like <button id="button" onclick="readfile()" />
How can I do that?
I tried in application.js
function readfile() {
alert('readfile work')
$.ajax({
alert('ajax work')
url: "/fileopen",
type: "POST",
##don't know what to do to make fileopen work
}
});
}
routes.rb
match '/fileopen', to:'static_pages#fileopen', via: 'get'
and it's seem nothing happen. Only the first alert work.
In answer to your question directly, you have to be able to handle the JS request in the controller. This is typically done by using the respond_to block in Rails, like this:
def fileopen
respond_to do |format|
format.js {
my_file = File.new("public/CHNAME1.txt","w")
my_file.write "\tfasf"
my_file.close
}
end
end
This code may give you some sort of a response with your current code, but it might be the case that you need to appreciate better how Ajax & Rails work in order to help you better
How Ajax Works
Ajax is a javascript technology which sends an "asynchronous" request to other pages on your website. By their nature, asynchronous requests are done completely independently of your main HTTP request, and basically act like a "pseudo" browser -- working in the background
Ajax is used to pull data from JS-enabled endpoints (which are handled with the respond_to function in Rails, which you can then use to modify your page in some way. A lot of people get confused with Ajax, but it's actually quite simple -- it's just javascript which pulls data from another page, allowing you to manipulate your page with that data
Using Ajax In Your Views
The reason why this is important for you is because you mentioned you didn't know what to do with the success callback of your app. Hopefully my explanation will show you that the success part of the $.ajax call should be used to append the data you receive from the controller on your page
This can be done in this way:
$("#button").click(function() {
$.ajax({
url: "/static_pages/fileopen",
type: "POST",
data: {name: $(this).val()},
success: function (data) {
// append data to your page
$("page_element").html(data);
}
});
});
I simply created a rails 3.0 scaffold and exposed it using json, and kept it running.
So if I hit http://localhost:3001/objects.json
I see json data in browser
Next I have one plain html which includes code.jquery.com/jquery-1.7.min.js. I opened this page in firefox(ubuntu), then opened the firebug console and tried following
var myurl = 'http://localhost:3001/objects.json';
$.ajax({
url: myurl,
dataType: 'jsonp',
error: function(data){ console.log("error:"+data); console.log("error:"+data.readyState); },
success: function(data){ console.log("success:"+data); }
});
I wanted to fetch same json here in success handler, what I have observed so far is
if specified dataType: 'jsonp'
I do get json response(checked with firebug:Net), same as I see in browser
I do not get success called
I do get error called, with status code = 4, and status = "success"
else I get
response blank
And one more thing, every time I get 200 back.
Any hints ...whats going on here?
Adding my server side code and log
code =>
# GET /objects
# GET /objects.json
def index
#objects = Object.all
respond_to do |format|
format.html # index.html.erb
format.json {
render :json => #objects.to_json, :layout => nil
}
end
end
log sample =>
Started GET "/objects.json?callback=jQuery17024293556233345082_1321347517236&_=1321347853199" for 127.0.0.1 at 2011-11-15 14:34:13 +0530
Processing by objectsController#index as JSON
Parameters: {"callback"=>"jQuery17024293556233345082_1321347517236", "_"=>"1321347853199"}
[1m[35mobject Load (0.1ms)[0m SELECT `objects`.* FROM `objects`
Completed 200 OK in 11ms (Views: 5.4ms | ActiveRecord: 0.1ms)
I think you using $.getJSON may be better
Maybe you returning result in the wrong Content-type (not jsonp). If you want jQuery to fire 'success' event regardless the Content-type, remove dataType parameter from ajax options
First, I am guessing it should be Object.all
I am assuming that the server your requesting from is different from the server that provides you with JSON data. i.e. different ports in this case or I see no need to use JSONP.
JSONP is not ajax but uses the src attributes in the script tags. If your trying to access information from the same server it dataType: json should be the approach.
If you are fetching information from a different server i suggest you add to the end of your url stream a ?callback=?.
With Jquery $.getJSON should be the way to go. For example
$.getJSON(url, data, function(response){
// Do something with response;
});
Reference http://api.jquery.com/jQuery.getJSON/
In reference to your last comment use this format.
$.getJSON("http://api.flickr.com/services/feeds/photos_public.gne?jsoncallback=?",
{
tags: "cat",
tagmode: "any",
format: "json"
},
function(data) {
$.each(data.items, function(i,item){});
});
Update
Just remembered this bit, If you have control over both servers are you sending JSONP responses? If this is your JSON data
response = { status:'success', message:'Successfully created object'}
To send it as JSONP you must wrap it up in a function(). Like
jsoncallback + "(" + JSON.stringify(response) + ");";
What this does is it executes the function generated by Jquery (this is done internally when specifiy callback=?. You can get the value by checking localhost:3001 logs) and passes your JSON data as parameters to that.
So if on the server side you are not generating JSON-P response it wont work.
We ran into a similar issue once long back, although with json, not jsonp. And it wasn't a cross-domain problem. Counting on my memory, I believe we had to remove respond_to from the controller and provide :status => 200 to render method to get it working. I'm not very sure, but you could give it a shot.