Rails, Prototype, and JQuery in Harmony (or how to replace Prototype with JQuery)
It has become common practice to use JQuery as the javascript library of choice for Ruby on Rails applications. If you have a Rails app already using Prototype, it usually isn’t feasible to replace it in one swoop. And sometimes, you just simply need both to work at the same time. Whether you want to use both in unison (not recommended as a long-term strategy), or you want to gradually migrate from Prototype to JQuery, it’s not as scary as you may think.
The secret is that it is difficult to get Prototype to play nicely with JQuery, while it is rather trivial to get JQuery to play nicely with Prototype. This may seem like a minor distinction, but it is one that will save you a lot of headaches.
Use Prototype/Scriptaculous with JQuery
First, in our application layout, we’re going to get rid of <%=javascript_include_tag :defaults %> and include each javascript file explicitly just to make things a little less magicky and a little more straight forward.
Now, we’ll add in JQuery (and JQuery UI while we’re at it, just for fun). You’ll want to grab the latest release from the JQuery download page (and the latest JQuery UI as well).
Right under that line, in your Rails application layout, we’ll insert the one-liner that makes JQuery play nicely with Prototype, YUI, etc.
// this allows jquery to be called along with scriptaculous and YUI without any conflicts
// the only difference is all jquery functions should be called with $j instead of $
// e.g. $j('#div_id').stuff instead of $('#div_id').stuff
var $j = jQuery.noConflict();
</script>
Try doing this with Prototype (especially if you’re using other scripts built on top of Prototype and Scriptaculous), and you’ll soon find yourself pulling out your hair.
If you simply want the ability to use both libraries together in your app, then congratulations, you’re done. You can now do this:
$j('#element_id').show();
Notice the first line uses the Prototype element id selector, $ with a Scriptaculous effect, and the second line uses the new noConflict JQuery selector $j.
Make Rails Use JQuery Instead of Prototype
Let’s assume that we’d like to phase Prototype out of our app in favor of JQuery. In addition to going through your application and replacing all of your Prototype code with JQuery code, you’ll need to take care of the Rails Prototype helper magic (note that when Rails 3 becomes the standard, this won’t be necessary).
This is really easy, thanks to the JRails plugin, which can be found on Github. Install it in your Rails project from your root directory.
Now, your Rails helpers, such as link_to_remote, form_remote_tag, etc. are using JQuery to build the AJAX code instead of Prototype on the back end. Isn’t Rails magic neat?
Caveat: Delayed Observer
There is one more step if you’re using the observe_form helper method. This helper relies on Prototype’s Element.observe method, which does not exist in the standard JQuery library.
No worries, someone has done the work for you already (not me). Just download and include the JQuery delayed observer plugin in your layout, and you’re all set.
Boot Prototype Once and For All
Once you’ve eliminated all Prototype/Scriptaculous code from your project (meaning there should now be no $ references in your entire project, only $j), you can simply remove it Prototype0+Scriptaculous from your project.
And just to celebrate, remove the var $j = jQuery.noConflict(); line from your application layout, and do a Find and Replace All $j with $ for your project. You have now ditched Prototype once and for all.
Tags: JQuery, JRails, noConflict, Prototype, Ruby on Rails, Scriptaculous


April 9th, 2010 at 2:19 am
[...] Rails, Prototype, and JQuery in Harmony (or how to replace Prototype with JQuery) [...]
May 19th, 2010 at 4:41 pm
Thank you for posting this information. Very helpful. I finally had time to try it, so I replaced the Prototype lib with JQuery using your instructions. So far everything is working well.
I noticed the jrails plugin’s JQuery and JQuery-UI were a bit out of date, so I added jquery-1.4.2.min.js and jquery-ui-1.8.1.custom.min.js to the jrails/javascripts directory, then renamed jquery.js to jquery-1.3.2.js and renamed jquery-ui.js to jquery-ui-1.7.2.js reflecting their versions. Then, I added two symlinks to the newer versions: “ln -s jquery-1.4.2.min.js jquery.js” and “ln -s jquery-ui-1.8.1.custom.min.js jquery-ui.js”. In the future, I can simply download the latest versions and redo the symlinks. That scheme may break at some point, but for now seems to be working.
May 19th, 2010 at 11:10 pm
That was silly! Of course, the JQuery javascript lib files need to be in the /public/javascripts/ directory. You can use the same symink scheme in /public/javascripts/
June 9th, 2010 at 10:51 am
Thanks for sharing this, that worked great!
June 9th, 2010 at 10:59 am
@Adrien: Glad you got it all figured out
@Derek: Awesome, glad it helped!
June 10th, 2010 at 3:58 pm
Hi, I think your site is very interesting. I found it via Google. Will definitely come back soon
June 10th, 2010 at 6:08 pm
I am an IT architect and do a lot of prototyping on new technologies before recommending them to our IT dept. Am a big RoR fan & have built some very satisfying apps.
Many thanks for your instructions – it prompted me to look at jquery and to start testing jquery in pref to prototype/scriptaculus.
One brickwall I have hit is that several apps I built relied on observe_form which is of course now deprecated. I have been on and off searching for a simple (I am not gun programmer) explanation of what I need to do in my ruby code to replace the observe_form call. Thus far I am no more advanced.
I looked at using the delayed observer plug-in but it mystifies me as it seems to do nothing the replaces the ajax call generated from observe_form. Am I expecting too much from it or do I still have to code a js ajax call with all the proper urls & actions stuff & place it in the delayed obserer js ?
The jquery.delayedobserver code found at your link …
// AJAX call <== am assuming this is saying code a native ajax call here ?
});
My observe_form code is …
:update => "replace_tbody",
:before => "Element.show('spinner')",
:complete => "Element.hide('spinner')",
:url => {:action => 'searching', :only_path => false} %>
I would be very grateful for an explanation of what I put where to get the original observe_form to work
Cheers
DSM
June 10th, 2010 at 6:11 pm
Seems the 1st post stripped out part of my observe_form code – I’ll try again here by adding spaces to the RoR tags …
:update => "replace_tbody",
:before => "Element.show('spinner')",
:complete => "Element.hide('spinner')",
:url => {:action => 'searching', :only_path => false} % >
June 10th, 2010 at 6:12 pm
Nup same happened again – seems I can’t post an RoR code snippet.
Cheers
DSM
June 11th, 2010 at 8:56 pm
@DSM: Sorry about the code, I should probably clarify in the blog that you can post code in the comments using these tags.
I tried to fix your original comment with the appropriate tags, but I’m not 100% positive I got it right, since Wordpress stripped out some of your original code.
I’m not really sure exactly what you’re asking. If you replaced Prototype/Scriptaculous with jQuery and then include the jQuery
delayed_observerplugin in your layout, you should not have to change your Railsobserve_formcode at all.June 15th, 2010 at 7:06 pm
Steve
Thanks for doing that, but I guess I am wondering how the observe_form code gets recognized as RoR 3.0 dropped the observe_form method ?.
I can’t see how it gets invoked if it is removed from RoR 3.0. I’ll do some more looking into your original post.
Cheers
Doug
June 15th, 2010 at 9:28 pm
Oh, I see, I didn’t realize you were trying to do this with Rails 3. Yeah a lot of things changed. Rails 3 uses these javascript plugin templates to plugin to the various js frameworks, to make it much easier to choose which framework you prefer. Here is the Rails 3 jQuery api file to make Rails 3 use jQuery for its helpers:
http://github.com/lleger/Rails-3-jQuery
But yeah, if using this with Rails 3, you’re better off using the jQuery.delayedObserver function directly as javascript instead of trying to use a Rails helper. So instead of the observe_form code, you’d do something like this in a
<script>tag://< ![CDATA[
jQuery('#my_form').delayedObserver(0, function(element, value) {
Element.show('spinner');
jQuery.ajax({
complete: function(request){Element.hide('spinner')},
data: value + '&authenticity_token=' + encodeURIComponent('/your-authenticity-token-here='),
success: function(request){jQuery('#replace_tbody').html(request);},
type: 'post',
url: '/searching'
})
})
//]]>
</script>
That being said, if you really want to keep using the
observe_formhelper in Rails, you can simply add the method to a file in your lib folder. Simply copy the source code for theobserve_formmethod and thebuild_observermethod, both of which can be found here:http://api.rubyonrails.org/classes/ActionView/Helpers/PrototypeHelper.html#M002189
June 16th, 2010 at 7:34 pm
Steve,
I really appreciate you following up on this as you have lifted the mist I was in re this change.
I do understand that the RoR 3.0 changes are for the better but boy they sure made me work hard to find ways around all the failed code I had from my 2.2 installations. I don’t mind doing this of course as it really focuses ones mind & is a great learning experience. I do feel sorry for the hordes of less experienced developers who will soon try migrating to RoR 3.0 & hit failures.
Posts like you are doing help sooo much and I am deeply grateful for you generosity.
Thanks
Doug M