My development setup
It’s something I always wanted to write about and also a response to Peter Cooper’s post on RubyFlow calling to write about tools that we use everyday to do Ruby on Rails development. I like the idea since there are a lot of options and finding right tool for the job is essential.
Let’s start:
Hardware
- MacBook Pro 15″ with Intel Core 2 Duo 2.40GHz and 2 gigs of RAM - absolutely enough. This is a decent laptop, the only thing which bothers me is its temperature, sometime it burns my hands, literally…
- Logitech VX Nano Cordless Notebook Mouse – the best notebook mouse ever, has the smaller receiver out there + I change batteries like twice a year, love it
Base software
- Arch Linux – it’s my 6 day with this distro actually, I’m a Gentoo fanatic but from time to time I try to use something different. I usually go back to Gentoo after a month or so. We’ll see how I’ll end up now. So far I really like Arch, it’s extremely lightweight, fast and stable. Software availability is as good as in Gentoo. It’s also easy to make your own packages which is crucial for Ruby developers since it happens that we need various non-standard stuff, like let’s say Nginx with Passenger support. I’ve got a feeling that this time I won’t go back to Gentoo
- KDE – it’s my desktop environment and one of the most important reasons why I’ve switched back from OSX to Linux. KDE’s window manager is highly configurable and gives you features like moving and resizing of windows via a special key + mouse move/click, custom settings per application / window class so for instance you can configure that console window will always appear on the third virtual desktop snapped to the upper-right corner of the screen, useful desktop effects ie “Present windows” which is something like Expose in OSX but you can filter out windows by typing key words, cool window transparency (you can alt+mouse scroll to change window’s opacity…it’s useful, believe me) and much, much more…I just can’t work without those things. Here are KDE’s apps that I use:
- Konsole – terminal emulator, very powerful, has tabs, horizontal / vertical view splitting, bookmarks and fully customizable look’n'feel
- KRunner – something like quicksilver for OSX
- Dolphin – file manager, supports remote protocols, in my opinion the best file manager ever
- KDiff3 – GUI for displaying diffs and merging, it’s my mergetool in Git
- KColorEdit – color picker and editor
- KRuler – on-screen ruler
- KSnapshot – for doing screenshots
- Klipper – a handy clipboard manager, supports custom actions
- Amarok – music player
- NetBeans – I use this great IDE even for writing tiny scripts, for me it’s the best choice. I’ve tried many other IDEs/editors including Eclipse, JEdit, RubyMine, TextMate and others that I don’t remember now and NetBeans works best for me. Key features are powerful editor with macros and great shortcuts, ctrl+click navigation, fantastic JavaScript support, debugger, test/spec runner and…support for multiple projects in the same window, something that most of the IDEs don’t have and I really need it. I use following plugins:
- Firefox – I’ve switched from Opera a long time ago because of Firebug, now I’m about to try out Chromium for normal web browsing and use Firefox only for the development. Plugins that I find useful:
- Firebug – must-have for every web-developer
- Web Developer – easy access to things like clearing cache, disabling JavaScript etc.
- Chat Zilla – IRC
- Read it Later – I never have time to read interesting things from Google Reader in the moment I find them so…I read them later
- Delicious – I still use it but rather for sharing bookmarks between work and home
Dev tools:
- GIT - probably the best SCM in the world
- QGit4 – sometimes I use this git gui to view history of a project
- ZSH with a pimped prompt for GIT
- Nginx with Passanger – better then script/server
- VirtualBox – I have 3 Windows virtual machines each with different version of Internet Explorer, only for testing of course
Communication:
- Skype – Linux version is very crappy, unfortunately I’m forced to use it
- PSI - great Jabber client
- TweetDeck – powerful Twitter client, Adobe AIR based
That would be it!
Unobtrusive JavaScript helpers in Rails 3
A while ago I have written a post about JavaScript helpers in Ruby on Rails and tried to explain why they are a bad idea. It’s hard to believe for me that it was almost 2 years ago! Since then so many things have happened in the Ruby world…Now Rails 3 is on its way and we already know what significant improvements and changes it will include. One of them is related to JavaScript helpers and the way how remote links and forms will be handled and I must admit that the new idea is absolutely great.
The new way is based on unobtrusive approach to JavaScript. This means that HTML code will be separated from JavaScript. I have checked out the latest sources of Ruby on Rails and found out that some of the work is already done. There is a new helper called AjaxHelper, it implements link_to_remote method which in the moment of writing this post looks like this:
def link_to_remote(name, url, options = {}) html = options.delete(:html) || {} update = options.delete(:update) if update.is_a?(Hash) html["data-update-success"] = update[:success] html["data-update-failure"] = update[:failure] else html["data-update-success"] = update end html["data-update-position"] = options.delete(:position) html["data-method"] = options.delete(:method) html["data-remote"] = "true" html.merge!(options) url = url_for(url) if url.is_a?(Hash) link_to(name, url, html) end |
What you see here will generate a clean markup with HTML5-compliant attributes prefixed with a word “data-”. If you are not familiar with them you can checkout a nice article by John Resig HTML 5 data- Attributes. Those attributes will instruct the additional JavaScript code how it should handle the behavior. Basically all links, buttons and forms that have the special attribute “data-remote” set to “true” will issue an AJAX request. There has been a discussion on the Rails on Rails Core group about how to implement corresponding JavaScript code. People are worried about its performance since finding all elements with data-remote=true appears to be slow in case of Prototype and jQuery. Moreover there is a problem of new elements that may be dynamically inserted after the page was loaded and all the event listeners were attached. Fortunately there is no need to be worried as our situation is a perfect example where we should use Event Delegation. DHH has already showed in his Rails 3 and the Real Secret to High Productivity presentation how links and buttons can be handled by Prototype library and it looks absolutely reasonable to me.
I would like to focus on jQuery though as it’s getting more popular even in the Rails community. Great example is my job where we use jQuery in every of our new projects. So how can we handle new remote links and forms using this popular library? Actually it’s ridiculously easy. Thanks to jQuery.live function we can easily use Event Delegation to handle AJAX calls. Just take a look at this sample of a markup that new helpers in Rails 3 will generate:
<!-- the new link to remote --> <a href="/users" data-remote="true">Users</a> <!-- the new remote form --> <form action="/users" method="post" data-remote="true"> <input type="text" name="login"/> <input type="submit"/> </form> |
Pretty clean, I really like it! Now let’s see how we can implement jQuery handler that will send AJAX requests:
var request = function(options) { $.ajax($.extend({ url : options.url, type : 'get' }, options)); return false; }; // remote links handler $('a[data-remote=true]').live('click', function() { return request({ url : this.href }); }); // remote forms handler $('form[data-remote=true]').live('submit', function() { return request({ url : this.action, type : this.method, data : $(this).serialize() }); }); |
The above code will send an AJAX request when you click on a remote link or submit a remote form. Note that it will work also with new elements dynamically inserted to the DOM. The example JavaScript code is the bare minimum of course, we could have something much more sophisticated. We will be able to specify success and failure handlers and also elements that should be updated with an AJAX response text (and probably much more!), hence the JavaScript is going to be more complicated.
This is definitely a step into the right direction. I’m looking forward to Rails 3!
Why JavaScript helpers in rails are evil
Ruby on Rails gained so much attention and appreciation mostly because it simplifies the development process of AJAX-driven applications. When I started to learn Rails I was already very familiar with other MVC-based frameworks, and actually I’ve created one myself (in PHP5) in my previous work. My framework also uses Prototype JavaScript library, so when l was learning Rails it was nothing new when I saw “Ajax.Updater(…)”. I remember that when I added first AJAX-feature in the Depot (it’s a tutorial application used in well known “Agile Web Development in Ruby on Rails” book) I was shocked about how simple it is, but then I looked into the HTML output and it shocked me once more…
JavaScript Helpers
These nice methods generate for you HTML with some addition of JavaScript code, one can say “You don’t need to know JavaScript to create AJAX web apps! Just use Ruby on Rails!”. It’s a catchy slogan, and in some way it’s true, you don’t need to know how Ajax.Request works, you just write link_to_remote and you’re done. In Rails API you can find 4 helper modules, all related to JavaScript code generation, and here they are:
* General JavaScript Helpers – actually there’s nothing interesting there
* JavaScript Macros Helpers – whole thing is deprecated in the upcoming Rails 2.0
* Prototype Helpers – probably the most popular methods, including link_to_remote and other AJAX goodies
* Scriptaculous Helpers – you know, drag’n'drop and visual effects goodies
When I first saw what link_to_remote helper creates I was really surprised, back then I said to myself “hey, that’s…just bad!”. Unfortunately I had quickly forgotten about my negative thoughts on JavaScript helpers, because “everybody” use them, and that’s a shame in my opinion. I don’t know why JavaScript helpers are included in the Rails core, maybe it was just a pure marketing trick or something
So, what’s so evil about JavaScript helpers?
DRY - ooooh reaaally?
We, the Ruby on Rails developers, use proudly our favorite MVC framework, we remember everyday about Don’t Repeat Yourself principle and other good and well known practices. How come that people like us write scary pieces of code like this:
<table id="users_list">
<% @users.each do |user| -%>
<tr id="user_<%= user.id %>">
<td><%= user.login %></td>
<td>
<%= link_to_remote(
'Delete',
:url => user_path(user),
:method => 'delete',
:confirm => 'Are you sure?',
:complete => "Effect.DropOut('user_#{user.id}')",
:failure => 'alert("Could not delete user: #{user.login}")'
)
%>
</td>
</tr>
<% end -%>
</table>
<% end %>
</table> |
Pretty common rhtml snippet, right?? (yes, I know, we use partials, but it’s just an example) Let’s have a look at the HTML output:
<table id="users_list">
<tr id="user_2">
<td>jane</td>
<td>
<a href="#" onclick="if (confirm('Are you sure?')) { new Ajax.Request('/users/2', {asynchronous:true, evalScripts:true, method: 'delete', onComplete:function(request){Effect.DropOut('user_2')}, onFailure:function(request){alert('Could not delete user: jane')}}); }; return false;">Delete</a>
</td>
</tr>
<tr id="user_1">
<td>john</td>
<td>
<a href="#" onclick="if (confirm('Are you sure?')) { new Ajax.Request('/users/1', {asynchronous:true, evalScripts:true, method: 'delete', onComplete:function(request){Effect.DropOut('user_1')}, onFailure:function(request){alert('Could not delete user: john')}}); }; return false;">Delete</a>
</td>
</tr>
<tr id="user_4">
<td>paul</td>
<td>
<a href="#" onclick="if (confirm('Are you sure?')) { new Ajax.Request('/users/4', {asynchronous:true, evalScripts:true, method: 'delete', onComplete:function(request){Effect.DropOut('user_4')}, onFailure:function(request){alert('Could not delete user: paul')}}); }; return false;">Delete</a>
</td>
</tr>
<tr id="user_3">
<td>peter</td>
<td>
<a href="#" onclick="if (confirm('Are you sure?')) { new Ajax.Request('/users/3', {asynchronous:true, evalScripts:true, method: 'delete', onComplete:function(request){Effect.DropOut('user_3')}, onFailure:function(request){alert('Could not delete user: peter')}}); }; return false;">Delete</a>
</td>
</tr>
</table> |
Where did DRY go? Hello? Why we don’t apply our OOP practices also to JavaScript? “Why bother!?” you might ask, well, BECAUSE IT MATTERS.
JavaScript won’t hurt you
Creating webapps without a good understanding of JavaScript is like working with ActiveRecord and having no idea what SQL is. I think you know what I mean. There are plenty of great JavaScript libraries, Ruby on Rails comes with Prototype and it makes writing JavaScript as easy&cool as writing Ruby code. Okey, here’s above example without redundancy, the quickest solution would be:
<table id="users_list">
<% @users.each do |user| -%>
<tr id="user_<%= user.id %>">
<td><%= user.login %></td>
<td><%= link_to 'Delete', '#', :onclick => "deleteUser(#{user.id})" %></td>
</tr>
<% end -%>
</table> |
And in application.js (or wherever else):
function deleteUser(userId) { if(confirm('Are you sure?') { new Ajax.Request( '/users/'+userId, { method : 'delete', on200 : function(){ Effect.DropOut('user_'+userId) }, on500 : function(xhr){ alert(xhr.responseText) } }); } return false; } |
Now, our ouput looks like this:
<table id="users_list">
<tr>
<tr id="user_2">
<td>jane</td>
<td><a href="#" onclick="deleteUser(2)">Delete</a></td>
</tr>
<tr id="user_1">
<td>john</td>
<td><a href="#" onclick="deleteUser(1)">Delete</a></td>
</tr>
<tr id="user_4">
<td>paul</td>
<td><a href="#" onclick="deleteUser(4)">Delete</a></td>
</tr>
<tr id="user_3">
<td>peter</td>
<td><a href="#" onclick="deleteUser(3)">Delete</a></td>
</tr>
</table> |
Advantages:
* We don’t have a redundant JavaScript code in the HTML output
* We are not limited to what link_to_remote generates
* We have a generic JavaScript function which deletes a user, we can make it even more generic and use successfully in other places
Disadvantages:
* Obtrusive JavaScript code in HTML
Progressive enhancement and unobtrusive JavaScript
I found out about this approach about half a year ago, when I started to use Dan Webb’s UJS rails plugin which makes an extensive use of LowPro library. I was very excited about its functionality, thanks to that plugin I’ve stopped using JavaScript helpers. UJS is a dead project now, you can find out why here but it doesn’t matter, thanks to it I’ve learned two important things:
- We can divide View layer into two sub-layers: the presentation (HTML+CSS) and the behaviour (JavaScript)
- Presentation layer can be extended using JavaScript by adding various behaviours to the DOM elements
Currently I don’t use UJS or pure Low Pro, instead I just code my JavaScript using Prototype and Scriptaculous. Let’s see how this looks in practice. Here’s how our users table example could be implemented using progressive enhancement and unobtrusive JavaScript code. First of all, we’re going to create plain HTML links, without onclick event and without even href attribute (I assume we’re writing an application which requires JavaScript to work):
<table id="users_list">
<% @users.each do |user| -%>
<tr id="user_<%= user.id %>">
<td><%= user.login %></td>
<td><a>Delete</a></td>
</tr>
<% end -%>
</table> |
Above rhtml template generates this HTML output:
<table id="users_list">
<tr id="user_3">
<td>peter</td>
<td><a>Delete</a></td>
</tr>
<tr id="user_4">
<td>paul</td>
<td><a>Delete</a></td>
</tr>
<tr id="user_1">
<td>john</td>
<td><a>Delete</a></td>
</tr>
<tr id="user_2">
<td>jane</td>
<td><a>Delete</a></td>
</tr>
</table> |
The very last thing to do is to add an actual functionality to our plain HTML code. Let’s create a simple module called Users, which will include method for deleting users:
var Users = { onWindowLoad : function() { $('users_list').getElementsBySelector('tr').each(function(userRow){ userRow.down('a').observe('click', Users.onUserDelete); }); }, onUserDelete : function(event) { if(confirm('Are you sure?')) { var userId = Event.element(event).up('tr').id.split('_').last(); new Ajax.Request( '/users/'+userId, { method : 'delete', on200 : function(){ Effect.DropOut('user_'+userId) }, on500 : function(xhr){ alert(xhr.responseText) } }); } } } Event.observe(window, 'load', Users.onWindowLoad); |
This way we:
- Write reusable and object oriented code
- Create clean and easy to maintain RHTML templates
- Have a clean separation between visual and behavior layers in our applications
- Decrease site loading time by writing less JavaScript (you can even compress it too)
- Improve general performance of our application’s UI
- Learn JavaScript!
The final word
I didn’t write anything about so called graceful degradation issue, leaving JavaScript helpers behind was the main reason for this article. If you totally disagree with me or/and you know an even better approach, leave a comment, I’m always open to a discussion.
