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

  1. 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”);
});
})

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

<% if @parts != nil %>

<% @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”

Pre: I turn on Firebug on Firefox

  1. I clicked on the “delete” link on an entry. Confirm dialog box pops
    up. I click “yes”
  2. I looked at the “Net” tab and I see the DELETE request. Clicked on
    the DELETE tab
  3. Looked at the header and json sub tabs and I see the expected data
    that I defined to return from the destroy action in the parts
    controller (above)

What am I missing?

The json data gets returned but somehow, jquery is not intercepting
it :frowning:
Is the ajax callback that I put in application.js errorneous/
incomplete?

Any good references (that work) with rails 3 UJS (ajax)?

My references were:
1)

2) http://rails3stuff.posterous.com/#!/59899595
3) Ajax Events | jQuery API Documentation
4) #205 Unobtrusive Javascript - RailsCasts
5 )
Unobtrusive JavaScript in Rails 3 — Simone Carletti
6) Redirecting...
7)
RailsDog.com is for sale | HugeDomains

What I have also tried:

Even tried defining app/views/parts/destroy.js.erb - with a simple,
alert(’ Calling destroy.js.erb ') - Does not work :frowning:

Please.

Thank you

Id Title Brand new? Manage

Hello, 7stud
thanks for that :slight_smile: Looks like a lot of GOOD info.
I will give it a go and revert :slight_smile:

  1. I do this:

<%=
javascript_include_tag(
http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js”,
“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.

  1. Following railscast #205 Unobtrusive Javascript, I put this file:

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.

  1. 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 that attribute:

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:

format.js {
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.

I don’t think this js will work:

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

You define an anonymous function here:

function(e, data, textStatus, jqXHR)

so no js can call that function.
Even if you give the function a name, what js calls that function?
I think your js may be a simple as:

(document).ready(function () {
alert(<%= @name %> + ’ has been deleted’);
$(‘a[data-method=“delete”]’).css(“color”, “red”);
});
})

If the document is ready(), which presumably it is because the user was
able to click on the link, then the alert() will execute and you will
update
the css. I actually think you could get rid of the ready() wrapper.

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:

In my case (i’m not definining .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?
  2. When @name has been defined in the format.js block, can I assume that
    the
    data just gets sent in the response and it is therefore up to any
    javascript
    to pick it up?

Thank you

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

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

Gordon Y. 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 the syntax for your 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 .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.

  1. 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.

and it is therefore up to any
javascript
to pick it up?

Thank you

public/javascript/application.js

$(‘.delete_part’)
.live(“ajax:success”, function() {
alert(" Part is deleted" );
}
);

controllers/parts_controller.erb

def destroy
@part = Part.find(params[:id])
@part.destroy
respond_to do |format|
format.html { redirect_to(parts_url) }
format.xml { head :ok }

end

end

views/parts/index.html.erb

<% if @parts != nil %>

<% @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),
                :method => :delete,
                'data-confirm' => 'Are you sure?',
                'data-remote' => 'true',
                'class' => 'delete_part'
        %>
    </td>
  </tr>
<% end %>
</table>
<hr>

<% end %>

<%= link_to ‘New Part’, new_part_path %>

each link generated is:

<tr>
<td>
  2
</td>
<td><a href="/parts/2">fddfdfdfdfdffd</a> </td>
<td><a href="/parts/2">Preview</a></td>
<td><a href="/parts/2/edit">Update</a></td>
<td>
  <a href="/parts/2" class="delete_part" data-confirm="Are you 

sure?"
data-method=“delete” data-remote=“true” rel=“nofollow”>Delete


When I clicked on the “Delete” link, the ‘ajax:success’ method
doesn’t run. If it did, the alert box with the message of ‘Part is
deleted’ does not show up at all.

  1. how do I detect on the browser (firefox with firebug) that
    ajax:success has run?
  2. what am I missing? I refered to
    Simple example of Rails 3 + UJS using Ajax to make a remote call, and rendering the resulting JSON object - Stack Overflow
    also but it didn’t work :frowning:

thanks :slight_smile:

KM

Id Title Brand new? Manage

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