I am new to the list and Rails (and Ruby, for that matter) and whilst
I was a bit skeptical due to the hype it’s causing, I am starting to
really like it and there seems to be a really active and friendly
community behind it which is an added bonus.
I have been writing web applications for a while now using different
languages and frameworks (including hand-written ones just following
best practices). I like it how Rails combines a lot of best practices
and how its conventions guide the user to writing good applications
(which I am convinced is possible on any kind of platform, but you
need to know what you’re doing, whilst Rails often takes you by the
hand and stops you from getting off track).
One thing I am having serious doubts about, though, is the usage of
JavaScript in Rails and I would appreciate your comments on my
thoughts. I hope this hasn’t been discussed before, I did my best to
try and search for comments on it, the only thing I did see mentioned
was an article by Dan W. about Ruby being the devil on the client-
sides shoulder, but it seems to have been taken off the web.
There is two things I would like to comment on:
-
How Rails creates a mess on the client-side violating the MVC
-
Why I don’t see the use of RJS
-
How Rails creates a mess on the client-side violating MVC
Whilst this has often been obscured by messy coding practices, you
can easily think of the client side of a web application as
implementing the MVC-paradigm.
M: HTML is the model. Good HTML does not include any presentational
information. (e.g. that is why nowadays there is a wide consensus
that HTML-tables are not meant to be used for layout)
V: CSS is the view. It defines how HTML data is presented on the
screen. I admit that a certain part of the presentation is pre-
defined by the ordering within the HTML, but stylesheets still allow
you to fundamentally shape a page
C: JS is the controller. It defines the beaviour of elements on the
page and in more advanced applications (especially AJAX) it
manipulates the HTML data.
However, HTML allows you to break the paradigm. You can include CSS
in your HTML (using style-tags) and you can include JS in your HTML
(using onclick, onmouseover etc. event-handler-tags). The fact that
MVC is so pervasive on the server side these days seems to indicate
that it has some value, though. So you can mess it up on the client
side but, as with any best practice, you usually realise after a
while that you’re better off when you don’t.
It’s become very common practice to keep your CSS out of your HTML.
For JS however, there is still a lot of mixing going on as it seems.
However, it is easily possible to keep your Javascript entirely out
of your HTML. The approach is often termed Unobtrusive JavaScript
(UJS). Sounds like a new feature, but essentially it’s just doing
what should always have been done. There is very good libraries
supporting it such as prototype and lowpro (especially its behaviour
feature).
Now, coming to Rails: On the server side it provides a very clean
implementation of MVC, strictling separating the three components. On
the client side, however, Rails creates a considerable mess on the
client side by heavily mixing Javascript into HTML (especially
promoted by RJS), thus mixing V and C. From the server’s point of
view HTML, JS and CSS are all part of the view. Fair enough. But from
the client’s point of view they’re not.
An attempt has been made by Luke R. and Dan W. by providing
the UJS plugin (http://www.ujs4rails.com/). However, Dan lines out
himself that it is a somewhat half-hearted attempt (http://
danwebb.net - The State (And Future) Of The UJS Plugin) The
plugin may create cleaner code in the end and may save you band-width
by keeping your JS out of your HTML (thus having to download it once
only). But to my mind, UJS is above all about programming practice,
about clean and maintainable code and the plugin doesn’t help that.
- Why I don’t see the use of RJS
I have spent a fair amount of time pondering about it, I have read a
lot of enthusiastic tutorial, but still I fail to see the use of RJS.
Essentially, RJS provides Ruby functions that output some bits of JS
code. Such as other functions (for example the form helpers, I hope I
am using the right terminology here) output HTML.
In terms of HTML that makes sense. HTML is a markup language, not a
programming language. There is no way to write functions, makros or
whatever in HTML. So if you have a certain complex HTML-construct
(e.g. a complex table or a custom control made up of various tags),
you would have to write it by hand again and again. So it’s useful to
have a Ruby function that does the job and reduces the work to a
single line of Ruby instead of say 20 lines of HTML.
However, JS is a programming language. If there is something complex
that you expect to be doing in many places, you can write a
Javascript function. So why do I need a Ruby function that renders
three lines of Javascript where I can just have a Javascript function
that reduces the three lines to one function call. Even more so, why
do I need a Ruby function like page.hide that translates to a single
JS call Element.hide.
That doesn’t make your code DRYer, it doesn’t make life easier. Yes,
I know, it saves you from writing JS. But JS is not difficult and
there are brilliant libraries and it’s well worth the effort of
learning. Because what price do you pay using RJS the way I see it
used most of the time?
- It creates an extra layer of complexity. It wraps Javascript with
Ruby (in a way you can think of RJS as compiling Ruby to Javascript). - it seems to me that with any serious JS-based application you will
quickly run into the limitations of RJS and you will need real JS,
anyway (Dan W. seems to think along similar lines: http://
danwebb.net - RJS Minus R) - when it comes to debugging you will still have to do it on the
client-side. You won’t recognize your own code, because you wrote it
in Ruby, but what you’re looking at, now, is JS. Firebug is a very
powerful and useful tool for debugging. But you will have to work in
Javascript. And you’re life will be much easier if your code is well-
structured within one JS-file and not spread out all over the place
inside HTML, in JS-files and in RJS-files that are downloaded using
AJAX on demand. That is a nightmare to debug.
So for the moment, for my first Rails project, my approach will be:
I will use Rails for the server side and I won’t let it mess with the
client-side. Rails belongs to the server and that’s where it’s
brilliant. For the client, there is HTML, JS and CSS already and used
properly they can be brilliant in their own way. I will treat JS just
as CSS: I will put it in the public folder and write only clean UJS
using prototype and lowpro which make it dead easy. I will debug
using Firebug on the client side.
I am thinking about writing my own version of
“javascript_include_tag :defaults”. My version would not only include
the default scripts but would also check if there is a js-file by the
same name as the controller in /public/javascripts. So /app/
controllers/user_controller.rb would have a corresponding /public/
javascripts/user.js that represents the client-side controller and is
included whenever a resource within the user controller is requested.
I am very keen on hearing your comments! Thanks
Stefan