Creating a :remote=>true post using AJAX rather than rails - ruby-on-rails

I've spent a day spinning my wheels trying to understand how Rails :remote=>true works. The question below seems complicated but I'm trying to understand this simple question with the information I provide:
How can I make an Ajax call that simply renders as JS without using :remote=>true?
From my understanding :remote=>true simply generates and handles an AJAX call:
My view looks like this:
opts in a very complicated way, creates a link with :remote => true. This is omitted for simplicity
.e_list
= opts.sort_link(:name)
= opts.sort_link(:description)
- e_list.each do |e|
.entry
= link_to(e.name, '#', class: 'select_e', data: {e_id: e.id})
= e.description
= paginate e_list, remote: true, params: {search:"j", com_id: com.id}
Gallery.js.erb
$('#com<%= #com.id %>').replaceWith('<%= escape_javascript render(partial: "shared/com", locals: {com: #com}) %>');
My Controller:
def gallery
if params[:com_id]
#com = #s.com.find(params[:com_id])
#com.filter = params
end
if c = #s.com.where(:_type => "Com").first
#current_e = c.entries(#user.app_id).first
#current_e.og_url = view_context.og_url(#current_e)
end
render :text => "foobar" if !#current_e
end
logs, after the user clicks on the pagination links or sort links (the key is those links have :remote => true)
Started GET "super long url" for 127.0.0.1 at 2012-05-04 16:08:42 -0700
Processing by CController#gallery as JS
SO I TRY TO RECREATE THIS WITH AJAX:
$('button.search').live 'click', (e) ->
search = $(e.target).attr('search-term')
success_callback = (results) ->
if results
console.log(results)
update_components(results[0].entry, '.entry')
else
$.ajax(
url: 'super long url that is exactly the same url as above!'
).done ->
return false
MY FAILED RESPONSE THAT DOES NOT RENDER AS JS, YET I THOUGHT :remote => true was simply an ajax call wtf?:
Started GET "super long url identical as the one that renders JS" for 127.0.0.1 at 2012-05-04 16:07:22 -0700
Processing by ContestController#gallery as */*
What is going on? How can I make an Ajax call that simply renders as JS without using :remote=>true?

Try
$.ajax({
url: 'your url',
dataType: 'script'
})
http://www.alfajango.com/blog/rails-3-remote-links-and-forms-data-type-with-jquery/

try
/screens/4fa02763dc1c82269c0001da/contest/gallery.js?app_row_id=5....
If you want the js from the response to execute in the browser you should need to do something like eval(response), but i'm just suggesting, I never done it and even know how to eval code of a string in javascript.

You could use jQuery to accomplish what you are trying to do:
/* your jquery file */
jQuery.ajaxSetup({
'beforeSend': function(xhr) {xhr.setRequestHeader("Accept", "text/javascript")}
})
...
$('#button').click(function() {
$.post('/controller/action', {
query_string1: value1
});
});

Related

Rails is rendering an empty partial from js.erb

I'm trying to render a partial from a js.erb file but nothing is shown in the view.
There is an AJAX call that triggers the report_announcement action in the announcements_controller when a button is pressed.
reports.js
$.ajax({
type: "POST",
contentType: "application/json",
url: "/announcements/report_announcement.js",
data: json_data
});
reports/_report_content.html.erb
<div id="report_announcements_container"></div>
announcements_controller.rb
def report_announcement
#announcement = Announcement.new(announcement_params)
respond_to do |format|
if #announcement.save
format.js {}
end
end
end
announcements/report_announcement.js.erb
I know that announcements/report_announcement.js.erb is rendering ok because I can see the logging statement in the console and also in the development.log as well as the report_announcement object being logged to the console.
<% announcement_json = #announcement.to_json.html_safe %>
var report_announcement = <%= announcement_json %>;
console.log('report_announcement');
console.log(report_announcement);
// this is where something is not right I think
$("#report_announcements_container").html("<%= escape_javascript(render partial: 'announcements/report_announcements', locals: { announcement: #announcement }) %>");
console.log('inside announcements....');
announcements/report_announcements.html.erb
This is where I'm having an issue because the logging statement for the partial is shown however nothing from the partial is shown on the page. I see in the development.log that the page rendered but nothing is actually shown in the view. The partial is not showing on the page in the report_announcements_container div.
<h1>test</h1>
<%= announcement %>
<script>
console.log('inside partial...');
</script>
You're using the wrong content-type in your ajax call. Rails recognizes both application/javascript and text/javascript as the :js format.
Also when you request a js format you actually have to execute the returned javascript for anything to happen in the client.
$.ajax({
type: "POST",
contentType: "application/javascript",
url: "/announcements/report_announcement.js",
data: json_data
}).done(function(data){
jQuery.globalEval(data); // Yeah eval is evil.
});
If you have done any "real" ajax calls before this will seem completely backwards - thats because it is. js.erb is a poor mans ajax framework for the javascript impaired which consists of a bunch of routes and views that mutate the DOM in the client.
Manually creating calls for a js.erb template is just a silly excerise in masocism. If you really want to use it create a form and use it send the request instead so that you can just leverage the javascript handlers that rails provide:
<%= form_with(url: "/announcements/report_announcement", remote: true) do |f| %>
# ...
<% end %>

Executing a rails .js.erb file from a jquery mobile form

My form spans several jquery mobile pages all within one file and wrapped by this form
new.html.erb
<%= form_tag submit_path, :method => :post, :remote => true do%>
create.js.erb
alert("Hello");
<% debugger %>
$.mobile.changePage("#confirm");
The create.js.erb gets hit as my console stops on the debugger, but the alert never fires and neither does the jquery mobile command.
My url goes from /new#confirm to just /new
I can do the (seemingly) exact same thing in a normal rails form and I get the alert.
Apparently you need to do this completely with Ajax to get rails to respond properly and have the js.erb execute:
In your form add
"data-ajax" => "false"
then
$('#submit_button').click(function(){
handleSubmit();
return false
});
function handleSubmit() {
$.ajax({
url: "/post_url",
type: 'POST',
cache: false,
beforeSend: function(xhr) {xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content')); $.mobile.showPageLoadingMsg("a", "Submitting"); },
data: $("#the_form").serialize(),
success: function(data){
handleResponse(data):
}
});
}

embed ruby in coffeescript? to render a partial on ajax success and append to body

My view has a link (remote: true) to the "new" action in the controller (HTTP "GET"), which responds with some data in JSON format...
I want to use AJAX and have my coffeescript file append a rendered partial on AJAX success...
here is the code:
$ ->
$('a').click (e) ->
e.preventDefault()
url = $(this).attr('href')
$.ajax
type: 'get'
url: url
dataType: 'json'
success: (json) ->
# I want to do something like this:
$('body').append(render :partial => "questionForm", :locals => {:q_id => json.q_id})
This is obviously not the correct syntax... is it possible to embed ruby into my js.coffee somehow? I've checked through everything else, and if I just do something like :
$('body').append(json.q_id)
it works - so the AJAX call and "new" action etc. all seem to be working.. Any ideas? Is it possible to do something like this?
If you're returning data from the server, then you probably want to use a client-side tempting system (handlebars, jquery-templates, eco) to take the json data and turn it into HTML.
If you want the server to render the HTML for you, then you can have the server render the HTML and use jquery to append it.
Something like:
<%= link_to "New Model", new_models_path, remote: true, id: "batman" %>
Then in your app/models/new.js.erb, you'd:
$("#batman").html("<%= escape_javascript(render partial: "models/form", locals: {model: #model})%>");

rails ajax request

I have a problem when sending the Ajax request. When you click on the link request is sent to the server 3 times and the answer did not come.
Why the request is sent three times to undermine?
Where did I go wrong in the formation of a query?
code:
run.html.erb
...
<%= link_to "Next", "#", :id => 'next', :class =>
...
run.js.erb
(function(){
$("#next").click(function(){
$.ajax({
type: 'POST',
url: '/engine/tff',
success: function(data){
alert("ok");
$("#question").html(data);
}
});
return false;
});
});
controller
def tff
respond_to do |format|
format.js render :text => "hello"
end
end
I am guessing the click event is being bound multiple times probably cos the script is being called multiple times. Not sure what is the reason for the multiple calls as I am not familiar with rails.
what you could do to avoid it is unbind the click event before binding it or use the on api.
function ajaxRequest(){
$.ajax({
type: 'POST',
url: '/engine/tff',
success: function(data){
alert("ok");
$("#question").html(data);
}
});
return false;
}
$("#next").unbind("click").bind("click",ajaxRequest);
or
$(document).on("click","#next",ajaxRequest);
also not sure if you were trying to bind on document ready and there is a typo in your code. but it should be wrapped like this:
$(function(){
$("#next").click(ajaxRequest);
});
One thing I ran into recently was that jquery tries to run the result, as the default dataType interprets the .js as a script, not text. You might need to add a dataType: "text" to the ajax call. I don't see how this translates into three calls though.
I thought returning false was supposed to prevent the click from moving on, but perhaps it is better form to use preventDefault() as apneadiving suggests.

Rails3 Update Boolean Checkbox from Index View

I'm building a simple tasks application for our company as part of an ordering system.
I have a list of tasks with a number of rules. Nothing complex... What I'm stuck on is the addition of a checkbox to complete the task. I want it done live, from the index view without having to hit submit..
Am really not sure even where to look. I figure I need to use ajax to do this - can anyone recommend a tutorial or tell me what I should be looking for.
Have also thought about a plugin, like the edit in place ones out there.
Thanks in advance
--- EDIT 1 --
Following advice from #pcg79 below, I've added the following to my application but am not understanding how I go out actually changing the status.
In my index view I have this:
<%= check_box_tag 'complete_task_1', '', false, { 'data-href' => tasks_path(#task) } %><
I've added the following to my application.js (added a # to get it to call properly)
$('#complete_task_1').click(function() {
$.ajax({
url: $(this).data('href'),
type: 'PUT',
dataType: 'html',
success: function(data, textStatus, jqXHR) {
// Do something here like set a flash msg
}
});
});
For lack of understanding, I added this to my tasks controller:
def completed
#task = Task.find(params[:id])
#task.status = true
end
Which seemed reasonable but wasn't sure how to actually call that in the ajax?
In my development log I can see it sort of working but it says this:
ActionController::RoutingError (No route matches "/tasks"):
-- EDIT 2 --
As per advice from #jdc below, I've tried adding the following to routes.rb:
get 'tasks/:id/completed' => 'tasks#completed', :as => :completed_task
But still get the RoutingError.
-- Slight Update --
Following the excellent advise from #pcg79 below, I've updated my files with the following.
Routes.rb
get 'task/:id' => 'tasks#completed', :as => :completed_task
Index.html.erb
<td><%= check_box_tag 'complete_task_1', '', false, { 'data-href' => completed_task_path(:id => task.id) } %></td>
Tasks controller
def completed
#task = Task.find(params[:id])
#task.status = true
#task.save
end
I get no errors in my browser, but my development log shows this:
ActionController::RoutingError (No route matches "/tasks"):
For a simple checkbox, this is hard work!!!
-- Another update --
Having played all day, I decided to see what would happen with a button_to instead, forgetting the ajax side of things. I put this in my code:
<%= button_to "Complete", completed_task_path(task.id) %>
And changed routes to:
match 'tasks/:id/completed' => 'tasks#completed', :as => :completed_task
Which worked a treat. Changing back to check_box_tag breaks it all again :(
Pretty much worked out it's the contents of my function. Having removed some code, I can update the css for a #:
$('#complete_task_1').click(function() {
$.ajax({
success: function(data, textStatus, jqXHR) {
$('#thing').css("color","red");
}
});
});
Any idea what I'd need to call my action?? J
If I understand what you're looking for (when the checkbox is checked or unchecked an Ajax request is sent to the server and the associated object is saved with the result of the checkbox), then yes you'll want to do it in Ajax.
With Rails 3 you're probably using jQuery (or, IMO, you should be). You'll need to implement a click event on the checkbox element. That click event, when it's fired, will do an Ajax call to your server. You'll want to do a PUT request since it's an update. You'll send the id of the object and the value of the checkbox.
There are a decent amount of sites that have examples of Rails and Ajax. This one (http://net.tutsplus.com/tutorials/javascript-ajax/using-unobtrusive-javascript-and-ajax-with-rails-3/) is good as it has you use the HTML 5 "data" fields which I like. There's also a bunch of similar questions here on SO. Here's one that's not Rails but will give you an idea of how to write the jQuery (AJAX Checkboxes).
Edit to answer question in comment
The checkbox can be wherever you want it since you're doing Ajax. If you want it on your index view, that's where you put it. Your checkbox will look something like this (please understand I'm not double checking my syntax or anything):
= check_box_tag 'complete_task_1', '', false, { 'data-href' => task_path(#task_1) }
Then your jQuery will look something like:
$('complete_task_1').click(function() {
$.ajax({
url: $(this).data('href'),
type: 'PUT',
dataType: 'html',
success: function(data, textStatus, jqXHR) {
// Do something here like set a flash msg
}
});
});
Second edit: I realized I forgot to actually send the value of the checkbox in the Ajax. You can do that and just call #task.update_attributes or you can make the url a specific method that only completes tasks.
Edit for updated question:
To explain my second edit, in order to update the task to be completed, you can do one of two things. You can either call a method that is expressly for setting the status attribute. Or you can call your normal, RESTful update method passing in :task => {:status => true} and call #task.update_attributes(params[:task]). You've chosen to do the former which, IMO, is fine.
So you have two problems. The first is that you aren't referencing the new route which points to your completed method. The second is that you aren't saving your object in the completed method.
To fix the first problem, you need to change the path your data-href attribute in the check_box_tag method points to. You don't want task_path. IIRC, you'll want completed_task_path(#task). The easiest way to find out the name of the path is to run rake routes in your Rails project's root directory.
To fix the second problem, just make sure to call #task.save at the end.
def completed
#task = Task.find(params[:id])
#task.status = true
#task.save
end
In your updated example, try replacing:
<%= check_box_tag 'complete_task_1', '', false, { 'data-href' => tasks_path(#task) } %>
with:
<%= check_box_tag 'complete_task_1', '', false, { 'data-href' => task_path(#task) } %>
Provided #task.id = 1, tasks_path(#task) returns /tasks.1, while task_path(#task) returns /tasks/1

Resources