#136
Nov 17, 2008

jQuery

How do you use jQuery with Rails? In this episode I redo episode #43 using jQuery instead of Prototype/RJS.
Download (16.9 MB, 9:49)
alternative download for iPod & Apple TV (11.9 MB, 9:49)

Resources

<!-- layouts/application.html.erb -->
<%= javascript_include_tag 'jquery', 'application' %>
// public/javascripts/application.js
jQuery.ajaxSetup({ 
  'beforeSend': function(xhr) {xhr.setRequestHeader("Accept", "text/javascript")}
})

jQuery.fn.submitWithAjax = function() {
  this.submit(function() {
    $.post(this.action, $(this).serialize(), null, "script");
    return false;
  })
  return this;
};

$(document).ready(function() {
  $("#new_review").submitWithAjax();
})
// views/reviews/create.js.erb
$("#new_review").before('<div id="flash_notice"><%= escape_javascript(flash.delete(:notice)) %></div>');
$("#reviews_count").html("<%= pluralize(@review.product.reviews.count, 'Review') %>");
$("#reviews").append("<%= escape_javascript(render(:partial => @review)) %>");
$("#new_review")[0].reset();
def create
  @review = Review.create!(params[:review])
  flash[:notice] = "Thank you for reviewing this product"
  respond_to do |format|
    format.html { redirect_to @review.product }
    format.js
  end
end

RSS Feed for Episode Comments 47 comments

1. Pedro Nov 17, 2008 at 00:38

Oh. Great! I am using jQuery for a long time and it is really better then Proto!
Here is jRails project: http://ennerchi.com/projects/jrails


2. Artūras Šlajus Nov 17, 2008 at 00:54

I can't really understand all those jQuery folks. You say it's much better but I can't see why. Prototype has improved A LOT with 1.6 release and is quite nice to use (and definately more nice looking to read).

I haven't heard any arguments why exactly jquery is so superior to prototype...


3. Peter Szinek Nov 17, 2008 at 00:57

Holy cow, I was wondering *yesterday evening* when will you release a jQuery railscast, and voilà! Railscasts make Monday mornings enjoyable again :-)

btw. recent statistics, generated from Rails Rumble suggest that jQuery is on the rise, and in fact, among the RR teams it was more popular than Prototype:

http://www.rubyrailways.com/rails-rumble-observations-part-ii-trends-in-gemplugin-usage


4. stijn goris Nov 17, 2008 at 01:06

Hi Ryan,

thanks for the great screencast!

A lot is talked about Jquery these days but is it worth making the switch? You also mention Unobtrusive javascript. What does it mean?


5. David Trasbo Nov 17, 2008 at 01:08

@Artūras Šlajus:

I agree. I don't understand why jQuery is so great either. I think what this episode missed is some kind of reason why you'ld switch from Prototype/script.aculo.us to jQuery.


6. Artūras Šlajus Nov 17, 2008 at 01:12

Especially when jQuery is just selector/whistles-and-dongles (effects) framework, and prototype has classes and inheritance.

I know you can use module pattern (http://yuiblog.com/blog/2007/06/12/module-pattern/) but it still offers no inheritance...


7. Artūras Šlajus Nov 17, 2008 at 01:14

@ stijn goris

UJS for short means, that you don't put you onclick or whatever attributes to tags, but instead call a single function at the end of the page, that attaches events to dom nodes. I.e. with $('id').observe('click', handler) as with Prototype.


8. Henrik N Nov 17, 2008 at 02:11

Great screencast as always, Ryan.

Some thoughts:

Instead of $(this).attr("action") you could do this.action (since "this" is the unadorned element). I tend to do that since while I love jQuery, I think the syntax can get a little busy, especially with attr().

In your custom submitWithAjax() function, you should add a return so you have 'return this.submit...', or add a 'return this' at the end. This ensures you can chain expressions, e.g. $('#foo_form').submitWithAjax().somethingElse();

Oh, and while Ajax submission is a great example, and sometimes you want to implement it yourself for more control, there is of course a plugin for it: http://malsup.com/jquery/form/


9. Henrik N Nov 17, 2008 at 02:18

Why I personally prefer jQuery over Prototype is mostly that I like unobtrusive JavaScript[1] and that the powerful selectors, event handlers and chaining make it easy to do very cool things with very little code.

I'd say (though there is likely a definition somewhere that differs) that unobtrusive JS is about keeping JS behavior separate from the HTML layer, just as you hopefully keep HTML and CSS distinct.

You do this by attaching events to the DOM when the DOM is ready instead of using onclick etc.

It also encompasses the idea of progressive enhancement, e.g. making a form or link work fine without JavaScript first, then attaching events or modifying the DOM from the JS layer so the experience gets better if you have JS, and still works if you don't.


10. MTH Nov 17, 2008 at 02:32

It looks complex.

I still didn't see reasons to switch to jRails.
Maybe someone has a link to complete pros & cons article?


11. Henrik N Nov 17, 2008 at 03:36

MTH: http://errtheblog.com/posts/73-the-jskinny-on-jquery (Ryan also linked it above) is a good advocacy article.

Note that you can use jQuery fine without jRails (as Ryan showed in the screencast), and many jQuery users would argue that Rails Prototype helpers/jRails helpers are bad because they produce obtrusive JS. In a sense, there's less reason to switch from to jRails than to just jQuery.


12. leethal Nov 17, 2008 at 03:52

More jQuery goodness: http://github.com/leethal/sample-rails-apps/tree/master/jquery_and_ajax


13. julien Nov 17, 2008 at 05:46

Excellent screencast, thanks a bunch


14. BadBoy_ Nov 17, 2008 at 07:04

ah...cool.
I just swapped from Prototype to jQuery (in a non-rails project) and it's very good =D


15. JQ Nov 17, 2008 at 07:53

How about security? Doesn't default rjs/proto config makes it harder to post unauthorized data.


16. Geoff Buesing Nov 17, 2008 at 07:54

Excellent stuff!

Ryan, note that accept header format recognition has been disabled by default:

http://github.com/rails/rails/commit/2f4aaed7b3feb3be787a316fab3144c06bb21a27

...so setting the accept header will have no effect (unless you re-enable it via use_accept_header) -- you'll need to append the correct format via an extension.

xhr requests, however, default to format.js, so no need to append '.js'


17. Ryan Bates Nov 17, 2008 at 09:25

There's a long list of pros and cons with jQuery, more than I could adequately cover in this episode. Here I just wanted to show how to use jQuery, not why.

In general though, if you enjoy working directly with javascript (instead of hiding it behind helper methods and rjs) and being unobtrusive is important to you, then jQuery seems like a good choice.

Ultimately it comes down to whichever you feel comfortable with.

@Pedro, oops, I forgot the jRails link, thanks!

@stijn, unobtrusive javascript means you don't interfere with the existing (working) HTML source by adding javascript inline. Instead you inject all the needed behavior using external javascript files.

@Henrik, thanks for the tips. I'll update the code with your suggestions.

@JQ, AFAIK security is no different than the prototype/rjs method. They are both doing the same thing: submitting an AJAX request and executing the returned javascript.

@Geoff, thanks for pointing that out! Not sure how I missed that commit.


18. derek Nov 17, 2008 at 11:00

thank you for getting to jquery, any idea on when merb will get a cast?


19. Gruszks Nov 17, 2008 at 11:09

Hi Ryan,
can you please make some validation beafore send request to server?


20. Dag Nov 17, 2008 at 12:27

"$(document).ready(function() {" can actually be shortened down to "$(function() {" since the default behavior of $() receiving a function is the same as ready on document.

However, I use "jQuery(function($) {", so that it wont be an issue if something overrides the $ variable - it is passed as an argument to the callback here so you wont be accessing the global variable inside the function body. Note that $ is the same as the "jQuery" variable. If you load jQuery last and need $ to be what it was before, you can also call "jQuery.noConflict();" to restore it.

Also worth noting is that semicolons are not often required, but encouraged.


21. Ryan Bates Nov 17, 2008 at 13:48

@derek, no merb cast planned (since I want to stay on topic of Rails), but if there's enough interest then maybe.

@Gruszks, I left off validations to keep things simple and because it didn't flow well. I'm also playing around with a few different ways to handle AJAX validations, so maybe it will be a separate screencast.

@Dag, thanks for the tips!


22. Antares Trader Nov 17, 2008 at 16:15

I just got done with a project where I used jQuery quite extensively. I find it a lot of fun to use, and easier the Prototype because it “is just selector/whistles-and-dongles (effects) framework.” My one big peace of learning from this project was to limit my use of 'id' in my html as much as possible. It is a real nightmare having to name every element you want to use. The selector in jQuery is much more powerful being a superset of CSS3.

My humble suggestion is to initially skip the id for anything that doesn't need it for CSS. If selection is to complex or ambiguous, first try adding a class to an element. Sense classes are reusable, it makes code reuse simple as adding a class to other elements. Your form for example could have been selected simply as $('form') all forms on a page will then submit with Ajax. If this is not appropriate, try $('#some_div form'). Or maybe add an 'ajax' class to the forms that you want to submit asynchronously.

The need to constantly name every element on a page will eventually drive you up the wall.


23. henry Nov 17, 2008 at 21:21

i think jquery is holding totally different ideas from Prototype.
jquery aims to maintain a minimal core for dom & ajax , but prototype is kind of ruby-clone on JS.


24. Stijn Goris Nov 18, 2008 at 00:53

Ryan, an AJAX validation screencast would be very helpful.


25. Franco Nov 18, 2008 at 12:28

Hi all. Is there some way to keep the prototype working together with jquery?

I would like to migrate to jquery, but I want to do it progressively.

Thanks to the railscast.


26. jblanche Nov 18, 2008 at 13:33

Wasn't there a problem when using Jquery and CSRF protection ?
Do we still need thos kind of hacks : http://errtheblog.com/posts/73-the-jskinny-on-jquery#comment_1154 ?

Great screencast by the way ;)


27. Artūras Šlajus Nov 18, 2008 at 14:02

By the way, can you achieve same technique with jQuery?

http://arturaz.net/blog/?p=545


28. Geoff Buesing Nov 18, 2008 at 16:04

@Ryan, correction on my previous comment -- looks like Accept header recognition was re-enabled with this commit:

http://github.com/rails/rails/commit/4ce9931f4f30045b2975328e7d42a02188e35079


29. cngg Nov 18, 2008 at 18:53

great!though I'm not use jquery.I like prototype


31. Ravi Nov 20, 2008 at 13:16

Franco,
just put jQuery.noConflict() in your application.js, and jQuery will relinquish control of the $ method


31. DanNewman Nov 20, 2008 at 16:46

Fantastic screencast! Helped me refactor some similar stuff I had been doing with Rails and jQuery. For those who'd like to check out another tutorial on this subject, my blog post:

http://polyrails.com/2008/11/11/steps-to-unobtrusive-rails-with-jquery/

Covers AJAX approach leveraging your existing rails templates (eg edit.html.erb) and reporting validation errors w/ jQuery unobtrusive JS.


32. Aditya Sanghi Nov 21, 2008 at 00:43

Is there a way to make the link_to :delete to be less unobtrusive? I really dont like how it generates a full form in place along with the authenticity_token which means i can't cache anything with that link.

One idea is that we put the authenticity_token in the meta tag/or some other suitable non-cached part of the page with an id and use jquery to scan for delete links and handle the click event on those links to make the correct call to the server along with the authenticity token in place. Anyone already worked on something like that?


33. Daniel Tsadok Nov 21, 2008 at 12:33

@Aditya - I had this same exact issue. Here is my solution:

http://pastie.org/320945

(Basically I load the edit form into the page and change _method to 'delete' instead of 'put', and submit :-P)

Ryan - thanks so much! I learned a lot :-)


34. Daniel Tsadok Nov 21, 2008 at 13:47

DanNewman's method looks better - putting the authorization token in the layout header.

Although I'm wondering if that's a security hole?


35. Neil Nov 22, 2008 at 13:48

I created an unobtrusive jQuery screen cast a little while ago inspired by these Railscasts.

http://thenexttrain.co.za/2008/08/screencast-ruby-on-rails-unobtrusive-jquery/


36. Thierry Nov 23, 2008 at 03:10

Very interesting video, as new to rails and new to javascript in general, I was wondering how to make both work together, but couldn't figure it out because of information overload. This screencasts sums it up pretty well, now all I have to do is learn a bit more javascript and jquery.


37. Jeff Squires Nov 23, 2008 at 19:41

I'm a grateful student of all of this. Please forgive me if I'm wrong, but shouldn't the submitWithAjax portion in application.js read:

  this.submit= function() {

and not

  this.submit(function() {
?

Isn't the idea to redefine the submit function?

Thanks for your efforts, I've learned alot from them.


38. Lou Nov 23, 2008 at 20:29

Great screencast, I am not using jRails for the same reason you mentioned. Jeff, submit(handler) is a shorthand for using bind('submit', handler). Take a look at the "Events" section found here: http://jquery.bassistance.de/api-browser


40. Aditya Sanghi Nov 24, 2008 at 23:23

In my comment earlier (#38), i mistakenly wrote if there was a way to make the link_to :delete "less unobtrusive". What I obviously meant, was to make it "less obtrusive". Oh the vagaries...

Daniel, thanks for the pastie, i'd like to see how your structure your html in the pastie as well. I think you are relying on the fact that there is a edit link around the delete link. How about relying on the href of the delete link itself?


40. Christine Nov 26, 2008 at 04:07

Thank you for this post. I was trying to make this work, but unfortunately the code in the create.js.erb is not being executed. The text in the message form is stored in the database correctly and I assume that the create.js.erb file is found, as I get an error if I delete it. The problem is that the popup alert does not appear.
Please help!


41. Jon Nov 26, 2008 at 04:40

Heads up on a little gotcha that had us scratching our heads since last night.

It seems the js.erb file still generates the file within a layout, which went against my assumptions of the layout being left out, a la rjs.

So if you're getting loads of html returned and you're thinking along the lines of some sort of mime type confusion, have a closer look at what's coming back and stick a render :template => false in your format.js block.

Cheers,

Jon


44. shmueli Dec 07, 2008 at 02:34

Thanks for the screen cast, Ryan.

I have been using a jQuery plugin called Ajax Forms, which I find much more intuitive. ($.ajaxForm)

check it out here:
http://malsup.com/jquery/form/


44. SteveI Dec 12, 2008 at 06:59

These screencasts always seem to fit in with what I am doing.

I was working through the jQuery in action book and wanted to use Rails rather than the jsp example. Your screencast was invaluable.

Thanks as ever.

I am looking to get into merb and I hope that the community starts to produce something as valuable as this.


46. Kirk Bushell Dec 22, 2008 at 17:01

jQuery vs Prototype argument... it really comes down to personal preference. I much, much prefer jQuery due to the far superior documentation of the library compared with prototype. Devs get spoilt with jQuery, it's far too easy when reading the examples.etc. I found with the prototype documentation I still had to piece things together in my head before I could write solutions. That's just my view of it, others may have had a different experience.


47. gaveeno Dec 27, 2008 at 11:10

fantastic screencast ryan! thanks for this and all the others.


48. wowgold Dec 30, 2008 at 20:01

<a href="http://http://www.swagvault.com/index.php?ref=2946/" target="_blank"><strong><span style="color: #00749e;">SwagVault.com</span></strong></a> is a diversified service provider operating the world’s largest secure network of buying and selling sites for massively multiplayer online game (MMOG) virtual currency and assets on the Internet. It boasts more than 350.000 customers and occupies over 70% markets shares on the following products: <a href="http://http://www.swagvault.com/index.php?ref=2946/" target="_blank">WoW Gold (World of Warcraft Gold), WOW Game Card &amp; CD- Key Codes, Warhammer Gold, Warhammer CD-keys, AOC Gold (Age of Conan Gold), EvE Isk, Maple Story Mesos, Lorto Gold, GW Gold, L2 Adena.</a> Since its founding in 2004 by consummate gamers, SwagVaulthas been an industry trailblazer and a market steward. In meeting the demand of game players to buy, sell and trade in-game items, SwagVault provides gamers with fast transactions, 24-hour customer service and guaranteed transactional security. SwagVault is dedicated to improving gamer services and fostering a more enjoyable.


49. wow gold Jan 02, 2009 at 18:31

Mmoinn.com is one of the world sales <a href="http://www.mmoinn.com"> wow gold </a> the best platform for trade, we give you more <a href="http://www.mmoinn.com"> cheap wow gold </a> and <a href="http://www.mmoinn.com/mmoinn_pl/"> wow power leveling </a>. Mmoinn.com trade in the safe and fast, you will get the confidence of guarantee!

Add your comment:

(SKIP THIS ONE)

(required)

(not shown)


(use pastie or gist for code)

sponsored by:
if you want to help:
required:
Get Quicktime Player