How to make AJAX responses work from the Rails side? - ruby-on-rails

The HTML form:
<form id="newsletter" method="post" action="/subscribers" data-remote="true">
<label for="email">Enter your email:</label>
<input type="text" name="email" class="text" />
<p class="btn"><span>Signup</span></p>
</form>
Note the data-remote="true"
The Controller:
class SubscribersController < ApplicationController
def create
#subscriber = Subscriber.create(:email => params[:email],
:ip_address => request.remote_ip )
respond_to do |format|
format.js
end
end
end
The View (subscribers/create.js.erb)
no clue what goes here to make it return normal AJAX response (or error if it encountered one
1. What do i put in the view to make it return normal ajax response or error? -- Is it even needed to begin with (can I return this without creating such views)
2. Is this the correct way of doing ajax with Rails?

This looks exactly like a question that I just answered today for another user... same model names and everything.
def create
#subscriber = Subscriber.new(#your params)
respond_to do |format|
if #subscriber.save
format.js { render :json => #subscriber, :status => :created, :location => #susbscriber }
else
format.js { render :json => #susbcriber.errors, :status => :unprocessable_entity }
end
end
end
Also, you shouldn't have to do the unless Subscriber.find_by_email(params[:email]) in your controller. You should just add validates_uniqueness_of :email to the Subscriber model.
In the .erb file that contains the form, you would add the following javascript:
jQuery(function($) {
// create a convenient toggleLoading function
var toggleLoading = function() { $("#loading").toggle() };
$("#your-form")
.bind("ajax:loading", toggleLoading)
.bind("ajax:complete", toggleLoading)
.bind("ajax:success", function(event, data, status, xhr) {
$("#response").html(data);
});
.bind("ajax:failure", function(event, data, status, xhr) {
//your code
});
});

A standard respond_to block (this allows both html and js) would be:
respond_to do |format|
if #subscriber.save
format.html { redirect_to(#subscriber, :notice => 'Subscriber created.') }
format.js # Not redirecting, just spitting out the JSON(js?) response (I believe).
else
format.html { render :action => "new" }
format.js # Not redirecting for js and this time return error response.
end
end
So what you have actually looks ok to me. Is it working ok or is there an issue?
The above should work with rails2 and rails3. Rails3 has a more succint syntax (of course) but given you are Rails2 I'll leave that for now.

Related

In Rails, how should I update a value in the database with ajax?

When the checkbox is ticked, I just want to update the 'Needed'value in the database.
And the script is list below
$('td div').find('input[type=checkbox]').click(function(){
$.ajax({
type: "PUT",
dataType: "script",
url: '/ecs/2',
contentType: 'application/json',
data: JSON.stringify({ ecs:{needed:'N'}, _method:'put' })
}).done(function( msg )
{
alert( "Data Saved: " + msg );
});
});
});
and the controller's code is standard.
# PATCH/PUT /ecs/1
# PATCH/PUT /ecs/1.json
def update
respond_to do |format|
if #ec.update(ec_params)
format.html { redirect_to #ec, notice: 'Ec was successfully updated.' }
format.json { head :no_content }
format.js
else
format.html { render action: 'edit' }
format.json { render json: #ec.errors, status: :unprocessable_entity }
format.js
end
end
end
The EC is the module's name, needed is the column's name. I just want to update a new value in the needed of ec with id=2 .
But right now, I always encountered the BAD REQUEST.
I'm not sure where is the problem.
for your checkbox (make it unobtrusive, it is just a quick example):
... onclick="$.post('/url', {omg_it_is_checked: $(this).attr('checked')})"
in routes.rb:
post '/url' => 'my_controller#my_action'
in controller:
def my_action
#....
#var = some.actions.here.with(params[:omg_it_is_checked]) #or update what you need
respond_to do |format|
format.js{render layout: false}
end
end
than you have to have an appropriate view my_action.js.erb with something like this:
$('#my_uniq_dom_id').html('<%= j render partial: 'new_piece_of_html' %>') #you can render nothing or flash something
and last we need is _new_piece_of_html.html.erb:
<div id="new_ajaxed_content"><%= #var %></div> <!-- or you can render checked checkbox, even with animation, or error message if in some reason it was not saved -->
voila! div#my_uniq_dom_id is updated with div#new_ajaxed_content after controller action
completely different approach - use this gem. it is simple solution for simple needs
cheers!

Ajax success event in Rails 3

Rails newbe here. I've got links that do ajax query to server:
<%= link_to g.name, g, :class => 'link link-to-gallery', :remote => true %>
JS view that loads data from partial:
$('#content').html('<%= escape_javascript render("layouts/galleries/show") %>');
And controller that operates with models and renders html and js:
class GalleriesController < ApplicationController
def show
#galleries = Gallery.all
#gallery_to_show = Gallery.find(params[:id])
respond_to do |format|
format.html
format.js
end
end
end
Ajax works fine, but I try to put callback after ajax completed:
jQuery(function() {
$(".link-to-gallery").bind("ajax:complete", function() {
alert(1)
});
});
and alert never shows. What am I doing wrong? Rails version is 3.2.11, Ruby version is 1.9.3p194
Update: When I'm using this code
jQuery(function() {
$(".link-to-gallery")
.on("ajax:before", function () {
alert("before")
})
.on("ajax:complete", function() {
alert("complete")
});
});
"before" alert fires but only once. If I press again I gain nothing. But ajax still works.
I think the problem is with your controller method that is not responding the async call with a success status message, 200.
Try this
def show
#galleries = Gallery.all
#gallery_to_show = Gallery.find(params[:id])
respond_to do |format|
format.html { :status => 200 }
format.js { :status => 200 }
end
end
If that doesn't work, try this.
def show
#galleries = Gallery.all
#gallery_to_show = Gallery.find(params[:id])
respond_to do |format|
format.html { :status => :ok }
format.js { :status => :ok }
end
end
It seems that I'm lame but smart enough to fix this. I had these links:
<%= link_to g.name, g, :class => 'link link-to-gallery', :remote => true %>
in the partial which gets re-rendered after ajax. So the callback functions that were attached to these links were flushed away after ajax. So I put link out of this partial and it works now.

Rails: Manipulate rendered JSON when using UJS

I enhanced my app by allowing AJAX form submissions, using UJS. Here is my create#product action:
def create
if Product.create params[:product]
respond_to do |format|
message = "New product created."
format.html { redirect_to :back, :notice => message }
format.js { render :json => { :status => true, :message => message } }
end
end
end
But I'm figuring out how to handle outputted JSON in my views/products/create.js.erb file??
I tried this simple console.log example, but without success (I mean, no console output):
$(function(){
console.log(xhr.responseText);
});
Thanks in advance.
You could use:
$('form.new_product').bind('ajax:success',function(event, data, status, xhr){
});
$('form.new_product').bind('ajax:error',function(event, xhr, status, error){
});
or even $('form.new_product').on(same_args).
Just make sure new_product is the actual class of your form.

Rails3 responding with js after json update

using http://blog.bernatfarrero.com/in-place-editing-with-javascript-jquery-and-rails-3/
The gem uses json to update, but how can I trigger my update.js.erb to update the different parts of my pages?
EDIT
Using this in an invoice page. every item in the invoice has a price field that can be updated with best_in_place.
I need to update the Total Price for line item and amount due for invoice only after field has been updated successfully.
Ended up with something like:
respond_to do |format|
if #item.update_attributes(params[:item])
format.html { redirect_to order_url(#item.order_id), :notice => "Successfully updated item." }
format.js { }
format.json { head :ok }
Edited best_in_place.js line #175
loadSuccessCallback : function(data) {
this.element.html(data[this.objectName]);
// Binding back after being clicked
$(this.activator).bind('click', {editor: this}, this.clickHandler);
if(this.objectName == "item") $.getScript('update.js'); // If its an item, call update.js.erb
},
I wanted to do the exact same thing with best_in_place pcasa. In the current version (1.0.2), the loadSuccessCallback function triggers an ajax:success event. That allows you to do this in your application.js:
$('.best_in_place')
.best_in_place()
.bind('ajax:success', function(e) {
// do your post-json call magic
});
You don't need a view update.js.erb. As ezkl already pointed out, you need to set the respond_to of your controller to json. In addition, you need to activate best-in-place in your public/javascripts/application.js
$(document).ready(function() {
jQuery(".best_in_place").best_in_place()
});
and add it in your view:
<td><%= best_in_place task, :name, :type => :input, :nil => "Click to edit" %></td>
I have a tutorial on Ajax with Prototype and JQuery on my own site - and the JQuery Part uses best-in-place: http://www.communityguides.eu/articles/15
Have you tried something along the lines of:
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to(#user, :notice => 'User was successfully updated.') }
format.json { head :ok }
format.js
else
format.html { render :action => "edit" }
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
end
end
I haven't tested this with the code in the tutorial, but the idea is that you have to tell the controller method to load the Javascript file. I'm not sure how this will interact with the redirect, but the principle is correct.

ajax request with form_remote_tag doesn't work

So I'm using a form_remote_tag to attempt an ajax form submission, like so:
<% form_remote_tag :update=> 'test', :url=> {:action=>'test_action'} do -%>
It renders with no apparent problem:
<form action="/pages/test_action" method="post" onsubmit="new Ajax.Updater('test', '/pages/test_action', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;">
The test_action action:
def test_action
if request.xhr?
render :text => 'some text'
else
puts 'nope'
end
end
When I submit the form(via the submit button, nothing weird like the jquery submit() event), no ajax request is made. The xhr check returns false. Help please??
In controller you should respond to specified format, js in your case. For example:
def create
#item = Item.new(params[:item])
respond_to do |format|
if #item.save
flash[:notice] = 'Item was successfully created.'
format.js
format.html { redirect_to(#item) }
format.xml { render :xml => #item, :status => :created, :location => #item }
else
format.html { render :action => "new" }
format.xml { render :xml => #item.errors, :status => :unprocessable_entity }
end
end
end
The best practice for now is to use unobtrusive javascript (UJS). There is no form_remote_tag in rails 3. UJS can be used with rails 2.3 as well.

Resources