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.

<%= javascript_include_tag 'prototype', 'scriptaculous', 'application' %>

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

<%= javascript_include_tag 'prototype', 'scriptaculous', 'jquery', 'jquery-ui', 'application' %>

Right under that line, in your Rails application layout, we’ll insert the one-liner that makes JQuery play nicely with Prototype, YUI, etc.

<script>
  // 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:

Effect.Fade($('element_id'));
$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

Update: This is actually even easier now with Rails 3. All you have to do is tell Rails to use the jQuery API javascript file instead of the Prototype API javascript file. See this Rails3-jQuery project on Github for using jQuery natively with a Rails 3 application.

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.

.script/plugin install git://github.com/aaronchi/jrails.git

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

Update: If you are trying to get delayed observer to work with jQuery in a Rails 3 application, see my comment below.

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.

<%= javascript_include_tag 'prototype', 'scriptaculous', 'jquery', 'jquery-ui', 'jquery.delayed-observer', 'application' %>

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.

<%= javascript_include_tag 'jquery', 'jquery-ui', 'jquery.delayed-observer', 'application' %>

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: , , , , ,

13 Responses to “Rails, Prototype, and JQuery in Harmony (or how to replace Prototype with JQuery)”

  1. Rails, Prototype, and JQuery in Harmony (or how to replace Prototype with JQuery) | RefreshTheNet Says:

    [...] Rails, Pro­to­type, and JQuery in Har­mony (or how to replace Pro­to­type with JQuery) [...]

  2. Adrien Lamothe Says:

    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.

  3. Adrien Lamothe Says:

    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/

  4. Derek Says:

    Thanks for sharing this, that worked great!

  5. steve Says:

    @Adrien: Glad you got it all figured out :-)

    @Derek: Awesome, glad it helped!

  6. Taisha Sikkink Says:

    Hi, I think your site is very interesting. I found it via Google. Will definitely come back soon

  7. DSM Says:

    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 …

    $('#autocomplete').delayedObserver(function(value, autocompleteObject) {
        // AJAX call  <==  am assuming this is saying code a native ajax call here ?
     });

    My observe_form code is …

    <%= observe_form  :my_form,
                        :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

  8. DSM Says:

    Seems the 1st post stripped out part of my observe_form code – I’ll try again here by adding spaces to the RoR tags …

    <%= observe_form :my_form,
                        :update     => "replace_tbody",
                        :before     => "Element.show('spinner')",
                        :complete   => "Element.hide('spinner')",
                        :url        => {:action => 'searching', :only_path => false} % >
  9. DSM Says:

    Nup same happened again – seems I can’t post an RoR code snippet. :(

    Cheers

    DSM

  10. steve Says:

    @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_observer plugin in your layout, you should not have to change your Rails observe_form code at all.

  11. DSM Says:

    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

  12. steve Says:

    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:

    <script type="text/javascript">
      //< ![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_form helper in Rails, you can simply add the method to a file in your lib folder. Simply copy the source code for the observe_form method and the build_observer method, both of which can be found here:

    http://api.rubyonrails.org/classes/ActionView/Helpers/PrototypeHelper.html#M002189

  13. DSM Says:

    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

Leave a Reply

You may include code snippets in your comment using this syntax.




Entries (RSS) and Comments (RSS)