You work for me, Computer.

By Brandon Bloom

Where Rails Rocks (and Where Python Doesn't)

Here’s a list of things I like about Ruby on Rails. Almost every single one of these are available in at least one Python framework in some form, but the best thing about Rails is how polished the pieces are and how well they all fit together. The whole is truly greater than the sum of its parts.

Fantastic OOBE

Rails has a fantastic out-of-box experience. Simply execute rails new and you’re off to the races with a directory full of goodies that every real web app needs: dependency management, build system, multi-environment configuration, development storage, logging, custom error pages, robots.txt file and more. See section 3.2 of the getting started guide for a complete list. Hell, they even fill out a .gitignore file for you! A place for everything and everything in its place.

Dependency Management: RubyGems

In the Python world, easy_install and its ilk are all kinds of broken. You can’t even uninstall a package! Luckily, there is Pip and Virtualenv, but assuming Pip supports all your packages, you’ve still got to make sense of dependency freezing and manually setup a virtual environment. With Rails, that all just works: rails server runs in a virtualized environment and loads gems as defined by your Gemfile; rails console for a repl. No need to muck with sys.path! Any seasoned developed has spent many an hour in dependency hell, but it is still hard to justify the infrastructure investment before writing a line of HTML. Bonus points for the “vendor” directory, in case you need to patch a third party package (or Rails itself) and want to keep it under version control.

Build System: Rake

gnu.org/software/make/manual/make.html”>Makefiles. A lot of people really hate them, but they are just so damn useful. Frequently, you need to transform some set of files into some other set of files, but only when they change. Makefiles help you do that reliably. They accomplish their feat explicitly by not being a programming language, but a dependency and build rule declaration language. I’ve seen a lot of attempts at build systems that aim to be idiomatic with respect to their host languages. Java has Ant and Maven. Python has Scons and others. Scala has Simple Build Tool. None of them are as good as plain old Makefiles. Then, I discovered Rake. Rakefiles rock. They are 90% Makefiles, and 90% Ruby. Rake expertly uses the features of Ruby to craft an API/DSL that looks a lot like Make declarations without compromising on general purpose programmability.

Markup and Style Sheets: Haml and Sass

Haml and Sass are so amazing, they ought to be illegal. Just click those links and check out the HTML and CSS comparisons. It is no contest. I never want to write HTML or CSS ever again. As far as I’m concerned, HTML and CSS are object code: to be generated by a compiler. Whenever I have to look at the generated code, it feels like I am reading assembly. Simply add gem ‘haml’ to your Gemfile, then start writing .html.haml files instead of .html.erb and .sass files instead of .css. Use html2haml and sass-convert to upgrade your crusty old markup and style sheets instantly.

Object Relational Mapper: ActiveRecord

I’ve discussed my preference for database schema reflection at great length, so I won’t reiterate here. I will, however, say that ActiveRecord makes simple things simple and complex things possible while embodying successful best practices in its various subsystems, like migrations. It doesn’t try to be everything to everyone, unlike SqlAlchemy. And it seems to be nicely onion layered for pealing back when necessary. For example, ActiveModel validations can be used on plain old Ruby objects. Which brings me to…

Form Handling: FormBuilder, params and mass assignment

I don’t need to learn and manage three different data marshaling techniques to map a database record to a web form. In fact, I don’t need to manage any. Schema reflection spares me in the model layer, FormBuilder/FormHelpers in the views, and the hash & array structured params in the controllers layer. Almost every user interaction boils down to interpreting a form’s worth of JSON-like data structures as an API call, implemented via a (secured) mass assignment to virtual attributes.

Templating: Layouts, Partials, and Helpers

When I’m getting my Haml on, I frequently want to run some non-trivial code. Feel free to shout about your separation of concerns religion, but I’ve got real things to worry about. Furthermore, we as engineers should be writing our production views/templates, not some hypothetical designer who is technical enough to write loops and branching statements, but not to be trusted with a function definition. Views are composed of markup and presentation declarations in the templates, presentation logic goes in helpers (which conveniently share scope with templates and controllers), and are neatly organized into partials. Simple, but effective.

URL Design: Routes

Rail’s routing system makes clever use of blocks to provide a hierarchical, declarative URL map that just makes sense to read. I used to design URLs in an indented text file and then map it to a list of regexps, but the routes.rb file is close enough to a spec and doesn’t require me to even think about regexes, ‘nuff said.

Authentication: Authlogic

Authentication is hard. Really, really hard. And boring. Really, really boring. But important. Really, really important. Everyone knows that the sign-up funnel is critical to get right and security is easy to get wrong. Most quality sites have a little bit of domain-specific special sauce in their authentication model. Trivial sign-up and log-in forms just don’t cut it. One size simply does not fit all for authentication front-ends, but the authentication back-ends tend to be pretty repeatable. Authlogic turns repeatable into re-usable, without the baggage of views you’re going to need to rewrite anyway. Thinking about authentication as CRUD operations on a user-session model blew my mind slightly. I had a full authentication system tuned to my needs up and running within two hours.

Authorization: CanCan

I hate ACLs. Role-based authorization simply has too much impedance mismatch for most problem domains. CanCan is a clever little library which makes zero assumptions about how permissions are represented. Simply declare a list of everything a user can do and how to tell if they may. Query with the can? function, or assert with the authorize! method. Beautiful.

Rope to Hang Yourself: Ruby Itself

One keyword in my previous post triggered much discussion: magic. The concept of magic is a topic for a whole ‘nother blog post (as I’ve already been hung a few times), but as several commenters pointed out: it’s all just Ruby. Between mixins, include, require, blocks, method_missing, symbols, and many other features, Ruby is a very capable internal domain specific language development toolkit. Most of the time, you don’t want a DSL. If you’re not an expert in both the host language and the DSL, there is almost certain confusion and maintenance danger. Most projects are either small or distinct enough to justify writing more verbose code that can more readily be understood by successors or even your future self. The gains of a DSL do not always outweigh the costs. Python excels at not supporting DSLs; it is basically executable pseudocode. However, when it comes to a task as common as web application development, it’s worth the time to develop or learn a DSL or two. Rails is loaded with DSL features and “magic” behavior that increases the learning curve, but also increases peak productivity.

Community

These sites have been invaluable: The Ruby Toolbox, RailsPlugins, Railscasts. The quantity and quality of Ruby libraries on Github continues to impress. The educational infrastructure is extensive. Somehow, the Ruby community seems to consistently be at the forefront of the biggest trends in software development. Much like Rails compared to other frameworks, the community distinctions are subtle, but meaningful. For example, Rubyists championed Git while Python adopted Hg. To the untrained eye, they are virtually identical tools, but extensive experience with both has convinced me that Git is significantly superior. I’m new to the community, but it seems like Rubyists tend to insist on quality and bet on the winning horses.

Other Random Things

  • Javascript and CSS minification are trivially easy with plug-ins
  • Static files are served with version stamps for better caching behavior
  • Console and file logging are usefully configured by default
  • git push heroku
  • rails.vim
  • ActiveMerchant looks awesome
  • Only been working with Rails for two weeks; lots more goodness to uncover

Just who the hell do I think I am?

I’m nobody. Just some opinionated computer geek working on a start-up. Not unlike many of you! My co-founder and I are currently participating in TechStars Seattle and hope to launch something killer come demo day, November 11th, 2010. We’ve got a grand vision for next generation enterprise collaboration software, but we’re starting small by focusing on making weekly status reports less painful and more useful. More details soon, but please visit http://www.thinkfuse.com. Thanks!

Imported Comments

Steve

You’ll probably remove this too (at least you read like a fan-boy) but … you don’t show where Python is lacking at all in this article. I’m not going to start a war but TurboGears has an equivalent to almost everything you listed there (Although I’m not so sure about Rake), and I was looking forward to the “comparisons” your title implies.

Brandon Bloom

I removed the previous comment because the author deleted it himself which left a vestigial block in the comment stream saying that the post was deleted.

He wrote “Why would you compare a framework to a programming language?” to which the answer is: because I’ve tried dozens of libraries and several frameworks in Python. Then I tried Rails. Python as an ecosystem lost out to Rails as a particular framework community for my needs.

To your comment: I don’t really think TurboGears does. Or at least, they are not first class citizens. For example, the documentation on form handling presents several options include FormEncode, ToscaWidgets, etc. It requires that I create an additional schema class where I declare widgets outside of the templates — or awkward @validate decorators.

Ixmatus

This is a poorly researched article. You’re comparing the language Python and it’s vast sea of tools to Rails the framework written in Ruby.

Pylons (which is also the foundation for TurboGears 2) provides all you have listed above, if not more. I’ve also noticed a strong tendency for Rails, Django, CakePHP, and many other “kitchen sink” frameworks to do much of the work for the developer and if I wanted to get around it – it becomes a day long hackathon of digging through docs, source code, and IRC logs.

Pylons, has its own quirks and dirty sides too; but I highly prefer having to spend a lot of up-front time programming/configuring my own framework environment “flavor” (and being able to use it across many different projects) then having it just be “Rails”.

Next time you post something like this, compare Rails to Django, or TurboGears, or Pylons; not just “Python”.

Brandon Bloom

@lxmatus: I am quite aware of the distinctions between a language and a framework. Thanks.

In this case, I am genuinely making the case that the Python web-development ecosystem as a whole has a story to tell which is less coherent and less attractive than the single framework: Rails.

I make this argument because I was able to use everything in this article without having to write a lot of glue code. I spent months researching and experimenting with Python libraries. Then I spent a week using Rails. Each of these things worked beautifully together without any heavy setup. The resulting complete stack aligned very closely with my preferences. And I’m a picky bastard: I tried a huuuge list of Python libraries before I found a stack I liked and I’m still not totally satisfied.

You can say “TurboGears has these” or “You should try Web.py” but that’s precisely the problem. If I install Ruby, install Rails, and then visit http://ruby-toolbox.com/ and choose the most popular plugin for each thing I need: I’ve got a highly pleasant, well integrated, stack in hours instead of months.

Steve

@Brandon … sorry for the accusation! I’ve watched far too many baseless arguments between the Ruby and Python groups, so maybe I’m a bit sensitive.

In any case, the example you gave is exactly the type of information I was expecting to find in the article. It’s very valuable to get the kind of comparative information you provide in your comment.

As noted by Ixmatus, I find both the frameworks to have their quirks … it’s the learning curve that you’re paying for when using either.

So I generally recommend TurboGears to people that already know Python and Ruby with Ruby on Rails for those that want to learn a 4th generation scripting language and use it with a RAD web framework. RoR definitely has the media hype and resulting community (or it could be the other way around).

John

Great list of reasons to love rails (may I add: migrations, UJS defaults, and restful controllers). The “python ecosystem” is a appropriate phrase and the whole “comparing framework to language” debate is out of context for this article. It is clear you taking the various frameworks and I-can-glue-this-library-to-this-one solutions into account in your support of the rails framework.

As far as rails doing too much work for the developer, that is the point. That is the whole point.

Paddy3118

Horses for courses. Python frameworks have their fanbois too!

Bruno Cezar Rocha

You probably does not know web2py.

web2py has everything you mentioned in that list.

http://www.web2py.com/book

William Brian Smith

I’d recommend devise over authlogic. Devises is build around warden which is kind of an authentication framework of sorts. Allows for pluggable auth strategies and already has a lot of extras(fb, twitter, imap, cas, openid). Also in rails 3.1, you’ll be able to flush the buffer before the page is done rendering, which should greatly increase load times. It will also come with a built in sprite system and css compression

Brandon Bloom

@William: I followed the advice in comment #10 here: http://railscasts.com/episodes/209-introducing-devise

I tend to want to customize pretty much everything heavily :–) Also, I also explicitly did not want any views/templates/etc done for me. However, I didn’t look at Devise closely. If I ever revisit our authentication, I’ll reinvestigate it.

Looking forward to those new features too. Thanks!