Posts Tagged ujs

Rails 3 – rails.js – document.on is not a function

I was busy converting an old app to Rails 3 today and I ran into some problems with Prototype and the new UJS stuff in Rails 3.  I set up a link_to with method delete like so:

= link_to "Delete", widget, :confirm=>"Are you sure you want to delete?", :method=>"delete"

With the new UJS setup in Rails 3, the link_to helper will create a tag like this when you use confirm and method delete:

<a rel="nofollow" data-method="delete" data-confirm="Are you sure you want to delete?" href="/widgets/123">Delete</a>

The new rails javascript file takes these parameters and uses Prototype to show you the confirm alert box and also makes it RESTful by using the DELETE method.  I was a bit perplexed when I did not see the alert box and this link used the GET method instead of DELETE.  I took a look at my error console in Firefox and got this error:

document.on is not a function

What the crap??  So I proceeded over to /public/javascripts/rails.js to see what was going on.  They bind the click event for the <a> using the following code:

  document.on("click", "a[data-method]", function(event, element) {
    if (event.stopped) return;
    handleMethod(element);
    event.stop();
  });

Apparently this does not work with the stable version of Prototype. It does work with Prototype 1.7, but I like the google hosted javascript files, and they use the stable version of 1.6. So I began questioning why one of my other apps was working just fine. Turns out that rails.js was changed with Rails 3 official release and I was using the betas for my other app. So I just took the old rails.js file from my other app and put it in this app. Here is an old version of rails.js on github

You could also upgrade to the 1.7 release candidate and use the newer rails.js file that ships with Rails 3 official, but I will stick with the Google hosted prototype. Hopefully this does not break anything else in my app ;-)

Tags: , , ,

Replacing link_to_remote with UJS in Rails 3 (Prototype)

Rails 3 has adopted Unobtrusive Javascript and moved all the _remote functions to a plugin.   They did this in an effort to remove all the inline spaghetti code produced by the helpers and provide a more modular way to deal with Javascript & Ajax. I must admit I like the convenience of the old helpers, but its not really the best way to do things if you are dealing with a complex app that uses alot of Javascript.  So anyways, you will get the following error if you try to use the link_to_remote function:  undefined method ‘link_to_remote’

In order to use UJS in your Rails 3 app, you need to do the following:

1. Use the new javascript file, rails.js along with your favorite javascript framework

In your layout, you can use the default javascript tag to include this and prototype:
The only problem with this method is that it may add javascript files that you don’t need and this adds to page load time.  I like to take advantage of the Google hosted javascripts.  Most people already have them cached and chances are Google will serve the files faster than your hosting company.  I am using some of the scriptaculous libraries so I include that tag too.   Here is what I use:
Make sure you put the rails js tag after prototype.  I wasted 30 minutes figuring that out.

Rails 3 makes it easy to use jQuery or Mootools if you prefer them over Prototype.  Just include them instead.


2. Use the forgery protection meta tags: <%= csrf_meta_tag %>

Rails uses these to prevent XSS attacks.  I don’t know the details, so I will not go into it.. but you need to have this helper which spits out 2 meta tags:
Don’t hard code these.  The helper provides a unique token.

 

3. Change your link_to_remotes to link_to and use the :remote parameter

Lets say you have a list of widgets and people can vote Yes or No as to whether they like the widget.  After they vote, it updates the box with a highlight and changes the text to show you the vote result.  Here is my big ugly Rails 2 version of this:

Here is what you do in Rails 3  (please ignore the ugly path.. we are renovating):

You now use a regular link_to tag and pass the :remote parameter as true.

 

4. Use a js.erb file instead of render :text=>”blah blah”

The link_to tag does not accept :update, :complete, etc., like the link_to_remote tag did.  You can drop in a js.erb file to handle this stuff instead.  I determine the text and color of the highlight in my controller action. /myapp/app/views/widgets/vote.js.erb

Rails sends this back to your page and the javascript is executed.  This is a simplistic solution and the first one I found to produce the same behavior as my original Rails 2 helper.  There may be better ways to do this, but for now this works for me.  Here are some resources that I found useful when figuring this out:

Ryan Bates screencast was very helpful and most of this stuff was “inspired” from that.  Props Ryan, good stuff as usual -> http://railscasts.com/episodes/205-unobtrusive-javascript

Simone Carletti has a good overview on UJS in Rails 3, and is more geared towards jQuery – http://www.simonecarletti.com/blog/2010/06/unobtrusive-javascript-in-rails-3/

Another jQuery example – http://joshhuckabee.com/jquery-rails-3

Tags: , , ,