Ajax and rails 3 UJS (jquery)

Hi, guys,

I'm in the midst of moving an app from rails 2.3.8 to rails 3.0.9.

Sadly, rails 3 no longer has javascript generators and I'm now forced to do more javascript.

For my project, I have selected jQuery as the javascript framework for my rails 3.0.9 app.

What I have done to have my app's deletion link (for each item) trigger an alert box when the deletion process is completed: 1) installed jquery-rails gem, deleted the public/javascript/rails.js file 2) added the line, "gem 'jquery-rails', '>= 0.2.6'" to my Gemfile, ran "rails generate jquery:install" 3) set up the controller action, destroy to respond by giving a json object when it's being called by ajax

  # DELETE /parts/1   # DELETE /parts/1.xml   def destroy     @part = Part.find(params[:id])     @part.destroy

    respond_to do |format|       format.html { redirect_to(parts_url) }       format.xml { head :ok }     format.js {       render :json => {:name => 'John'}     }     end   end

4) added the following to application.js

// Place your application-specific JavaScript functions and classes here // This file is automatically included by javascript_include_tag :defaults

$(document).ready(function () {   function(e, data, textStatus, jqXHR){    alert(data.name + ' has been deleted');   $('a[data-method="delete"]').css("color", "red");   }); })

5) the view, app/views/parts/index.html.erb has deletion links for each part item:

<% if @parts != nil %> <table border="0" id="table-lined">   <tr>     <th>Id</th>     <th>Title</th>     <th>Brand new?</th>     <th colspan="5">Manage</th>   </tr>

    <% @parts.each do |part| %>       <tr>         <td>             <%= part.id %>         </td>         <td><%= link_to(part.title, part) %> </td>         <td><%= link_to 'Preview', part %></td>         <td><%= link_to 'Update', edit_part_path(part) %></td>         <td>             <%=                 link_to 'Delete',                     part_path(part.id),                     'data-method' => 'delete',                     'data-confirm' => 'Are you sure?',                     'data-remote' => 'true',                     'class' => 'delete_part'             %>         </td>       </tr>     <% end %>     </table>     <hr> <% end %>

When I run "script/rails server"

1) I do this:

<%=     javascript_include_tag(       "http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js&quot;,       "jquery.rails.js"     ) %>

No gem needed. You can read here about the advantages of using a google link:

http://encosia.com/3-reasons-why-you-should-let-google-host-jquery-for-you/

Note that railscast #205 Unobtrusive Javascript also uses a google link rather than a gem.

2) Following railscast #205 Unobtrusive Javascript, I put this file:

https://github.com/rails/jquery-ujs/tree/master/src

in the same directory as the default rails.js file, and I named it jquery.rails.js. Note how in 1) I link to jquery.rails.js. That way you don't need to delete the prototype file.

3) In rails 3, you use respond_to/respond_with

class SomeController < Application Controller

  respond_to :html, :xml, :js

  def some_action     respond_with(@user)   end

See here:

4 & 5) It's my understanding that having data-remote="true" in an html element causes an ajax request to be sent to the specified action. After the action executes, the *default* is for rails to render a page called action_name.js.erb, which sends the js on the page back to the browser, and then the browser executes the js. However, you told rails not to preform the default:

render :json => {:name => 'John'}

So rails sends that text back to the browser--rather than the js in action_name.js.erb. I can think of two solutions:

1) json is the same format as a js object. So you can just put your json in your js in action_name.js.erb

2) You can write this in your controller:

  @name = "John"

and then use @name in action_name.js.erb.

In other words, you are currently wanting to send two responses in response to one ajax request: the json and the js in some_action.js.erb. Rails is sending back one response.

Hello, 7stud thanks for that :slight_smile: Looks like a lot of GOOD info.

I will give it a go and revert :slight_smile:

Hello, 7stud, I followed your recommendations and I managed to get good results.

When I define the return data and then not put any “render” in the controller action, it works.

------------------------------------ parts_controller.rb extract starts ----------------------------------------

DELETE /parts/1

DELETE /parts/1.xml

def destroy

@part = Part.find(params[:id])

@part.destroy

respond_to do |format|

format.html { redirect_to(parts_url) }

format.xml { head :ok }

format.js {

@name = ‘John Malko’

}

end

end

------------------------------------ parts_controller.rb extract ends ----------------------------------------

----------------------------------- application.js extract starts ---------------------

$(document).ready(function () {

$(‘a[data-method=“delete”]’).live(‘ajax:success’,

function(event, data, textStatus, jqXHR){

alert(data.name + ’ has been deleted’);

});

})

----------------------------------- application.js extract ends ---------------------

Questions:

Gordon Yeong wrote in post #1020881:

Hello, 7stud, I followed your recommendations and I managed to get good results.

When I define the return data and then not put any "render" in the controller action, it works.

------------------------------------ parts_controller.rb extract starts ----------------------------------------   # DELETE /parts/1   # DELETE /parts/1.xml   def destroy     @part = Part.find(params[:id])     @part.destroy

    respond_to do |format|       format.html { redirect_to(parts_url) }       format.xml { head :ok }       format.js {         @name = 'John Malko'       }     end   end ------------------------------------ parts_controller.rb extract ends ----------------------------------------

----------------------------------- application.js extract starts --------------------- $(document).ready(function () {     $('a[data-method="delete"]').live('ajax:success',       function(event, data, textStatus, jqXHR){         alert(data.name + ' has been deleted');       }); }) ----------------------------------- application.js extract ends ---------------------

Where does your the syntax for the event name 'ajax:success' come from? In prototype you can use the event name 'dom:loaded', although I can't find much information about where that name comes from either, but in any case that is prototype--not jQuery.

Questions: ----------------

In my case (i'm not definining <action>.js.erb) as all I wanted was to have the deleted entries fade out (I defined some javascript in application.js), 1) for js format, can I safely assume that @name gets sent out in the response as :json since the request was a xhr request?

No. json format has nothing in particular to do with ajax.

2) When @name has been defined in the format.js block, can I assume that the data just gets sent in the response

No. Defining a variable and assigning it a value doesn't send anything to the browser. Instead, rails will attempt to render the page 'action_name.js.erb', and of course on that page any @ variables created in the action will be available.

Where does your the syntax for the event name 'ajax:success' come from? In prototype you can use the event name 'dom:loaded', although I can't find much information about where that name comes from either, but in any case that is prototype--not jQuery.

I picked it up from http://railsdog.com/blog/2011/02/28/callbacks-in-jquery-ujs-in-rails3/

hi, guys,

Havent’ touch the source code for a week. For some weird reason, when my destroy method has run, my ajax:success js action does not run (ie. an alert box with a message, ‘Entry with has been deleted’).

On the browser (assume firefox with firebug), how do we find out if ajax:success was triggered?

thanks

KM

public/javascript/application.js

I figured it out!

Left out the "$(document).ready(function(){ ... });" lines in application.js.erb.

If anyone gets stuck like this, think of the line above.

Hope it helps :slight_smile:

Gordon