Thoughts about Rails from a Django guy
July 25, 2010
My first and still my favourite programming language is Python and Django has so far been my framework of choice for my personal projects. Nevertheless, when a good friend of mine scrounged a free website off me a little while ago, I didn’t do what I normally do when friends ask for freebies: setting up another instance of WordPress on my server and let them choose a free template. Instead I decided to write my own CMS for his website using Rails.
I had read and heard lots of praise about Rails and was planning to add another skill to my list. I thought to myself that if I’m doing him a favour he can put with the slow speed of a developer learning a new language and framework.
Whilst working through the documentation and tutorials I couldn’t help comparing Rails to Django, since it is the framework I’m most comfortable with and it takes a little time to unwire your assumptions and expectations of how a web framework ought to work. So, basically this is a one-sided mini-review of Rails.
The Ruby language
I didn’t know any Ruby before this project but everybody knows these days, that the blogging engine is the new ‘Hello World’. Ruby and Python are more alike than they’re different. Both are interpreted, use duck typing and both impose little structure on the source files. Ruby is slightly less readable to me due to the following things
- too many sigils
- multiple possible function/method calling syntaxes
- the block syntax – it took me a little while to get used to but I’ve grown rather fond of it
I’ve read that Ruby lacks the amount of non-web libraries that Python has. But that doesn’t bother me since I almost exclusively do web stuff. I’m simply not clever enough to have a use for for SciPy and NumPy.
What I don’t like about Rails
ActiveRecord
The abovementioned project obviously didn’t need a really complicated data model: a handful of entities with some simple many-to-ones. Particularly because ActiveRecored markets itself as a simpler solution to heavyweight enterprise ORMs like Hibernate, I found setting up this schema surprisingly difficult. Compared to Django, Rails introduces a few new concepts, which took me little bit to get my head around it.
- separation of schema and model: in Django the model is the schema and I couldn’t really understand why those two things should be separate
- migrations: I can see how this could come in handy but in my case this was yet another extra thing I had to keep tabs of
- if you have a many-to-many relationship you will have to define a join table yourself; in my view this is exactly the type of thing that an ORM at the abstraction level of ActiveRecord should take care of
Particularly due to that last point I kept thinking that ActiveRecord is just SQL rewritten in Ruby.
Templating
Using pure Ruby in .erb templates surely is powerful but to me smells of Java Scriptlet, doesn’t it? I subscribe to the view that the template language is for designers and should only allow safe constructs. Not really a biggie, but rather a little quirk.
No built-in admin
This is something I love about Django and find kind of a deal-breaker with Rails. Django gives you great looking admin interfaces for editing your data out of the box. It takes you 95% of where you want your admin area to be and I myself never had the need to customize the template. I hear that with the introduction of the newforms library it is now not so hard anymore to write your own admin views. All in all, I’m pretty surprised that Rails hasn’t even got anything remotely similar. (Maybe I have given up looking too soon? Let me know in the comments.)
What I like about Rails
Directory structure
Rails is pretty good at giving you a feeling of where your files ought to be in the directory structure, by neatly giving you a controller per model. Also, I quite like the distinction between the top level folders config, app, db, test etc. This is, in my opinion, something of a weak point in Django, where I never quite understood where stuff is supposed to live. Yes, you say that you should be separating your code into individual Django apps but I think that is the wrong abstraction level and like the concepts of plugins somehow better. That might be the Java developer in me speaking – a gem is much more like a JAR.
Dependency management
It’s great that you can specify the needed gems for your application and even tell the runtime that you need a specific version of Rails. I haven’t tried it but it seems that the needed gems are automatically installed if they aren’t already. Managing your dependencies is kinda non-existent in Django.
Grass isn’t always greener
Well, I don’t really know what I expected but Rails does not magically solve all problems and does not trivialise web development. On the other hand I wasn’t unhappy with Django – I just wanted to expand my horizon.
Rails certainly boosts your productivity but I found a few things, mostly around ActiveRecord, a bit strange and counterintuitive. I can’t say that I have fallen in love with Rails but it is a solid framework worth its popularity. Bear in mind that this is me speaking after using Rails for about 2 weeks – I’m sure I have only scratched the surface of the things that Rails can do for me; I hear that the testing and deployment tools are fantastic. Maybe I’ll do a follow up post on how my view changed after I used them.
Node.js is better than both, Ruby and Rails are just the new Cobol…
that comment is undefined
apple and oranges?
nodejs is not a webframework
Award for the dumbest comment.
Do you know what a webframework is?
you’re clever
As a long-time Rails developer I can’t agree more on the ActiveRecord deficiencies, which arguably is one of the most-used parts of Rails. DataMapper (an alternative Ruby ORM) gets all of those ‘right,’ and thankfully Rails3 supports drop-in ORM replacements.
An auto-admin is still lacking though. There’s a few contenders, but it should be builtin & as awesome as Django’.s
You may prefer datamapper based on your feelings about rails. I too prefer the model and schema to be defined in the same location. And the option for automatic migrations is killer.
Also other frameworks Sinatra are a little leaner than Rails and may fit what you’re working on better.
I agree with Mark that Sinatra is really nice and lean, so if you don’t need a lot or you just want to do it your own way then it’s a good fit.
Regarding your point about Rails vs. Django directory structures: for useful, non-trivial directory structure examples for Django projects, be sure to see the Pinax project: http://pinaxproject.com/ They’re very well thought-out, separating media, reusable apps, common templates, etc.
Check out the admin_data plugin for editing your data live:
http://github.com/neerajdotname/admin_data
I’m new to Groovy / Grails, but I have to admit I’ve been really impressed with it.
Groovy is probably more similar to Ruby than any other language, but incredibly easy to read; especially if you come from Java… which I don’t (actually, I pretty much have a hate/hate relaitonship with Java).
GORM is a dynamic front-end to Hibernate, which itself is very mature, and many-to-many relationships “just work”.
Groovy / Grails — “I’m lovin’ it!” ™
I’ve been playing around with Grails as well and I’m also very impressed. It’s been an amazing experience so far.
Surprisingly unbiased article for someone whose first language is still his favourite (I was hesitant to even start reading article). Just couple of things:
Not sure about “too many sigils”. Plain local variables and method arguments don’t use them.
Blocks – IMHO the most powerful Ruby feature. But you have to use it for a while to really appreciate them.
Admin – I really missed it (I also first learned Django), but there are replacements. Check out activescaffold, for example. Perhaps not as powerful as Django’s, but if you find yourself needing more powerful admin interface, you probably have to build it yourself.
I hope you don’t get me wrong – both Python and Ruby are great languages and I’d be happy if any of them ever gets the attention that they both deserve.
Here’s my thoughts on this post:
**Sigils** give you a lot of flexibility in a language such as Ruby. If you want to define a variable that’s local to the method then you use a local variable (`var`) and if you want to define something that’s local to the instance (the object itself) you use an instance variable (`@var`). To me, the sigils are what makes this language powerful and they shouldn’t be listed as a negative point against Ruby.
**Method calling** can be done in (to my knowledge) 3 different ways. Let’s say you have a method defined like this:
def moo(bar)
puts “Moo! ” * bar.to_i
end
To call this method you can use either `moo 1`, `moo(1)` or you can use `send` to call it (which you’d only do if the first argument of send is dynamic, or the method is protected: `send(:foo, “1″)` Whilst it’s a little confusing to start off with, you don’t have to call methods in any particular way and I think that’s a great strength of Ruby.
**The block syntax** is something fun to understand too. If you want a single line block you’d do this:
dwim { generate_facebook }
Or if you wanted a multi-line block you’d use `do` and `end`, like this:
dwim do
generate_facebook
end
Both syntaxes are identical. Then there’s block variables that look like this:
dwim { |site| generate(site) }
or
dwim do |site|
generate(site)
end
The different block syntax is very helpful. In Ruby if something is best put over multiple lines, then do it that way. The language affords you that ability.
**Non-web libraries** Ruby has a wide collection of libraries (Rubygems) and I’d be surprised if it didn’t have something complimentary to SciPy or NumPy, although I can’t profess to know if they exist.
Now on to the Active Record (yes, with a space [/pedantic]) stuff.
**separation of schema and model** is great imo. If you have a 50 column schema and you’ve got the definition at the top of your model, then isn’t that 50 lines of crap you’re going to have to go past to get to what you’re most likely wanting to see? I’ve worked on projects *in Rails* with models like this and it just isn’t pretty. The separation is very, very awesome and you don’t know what you’ve got ’till it’s gone.
**migrations** are effectively version control for your database. Don’t think of it as “another extra thing I have to keep tabs of”, they come in real handy for moving the schema of your database forward (or backwards).
**many-to-many relationship** using has_and_belongs_to_many is a little … “fun”? You’re right that it won’t define the table for you because, as we’ve discussed previously, the models (where the relationships are defined) and the schema are two separate beasts. The best route to fixing this would to use a has_many :through and create a join **model** as well which will in-turn create a join **table**.
**templating** is something many people unfortunately abuse. It’s there to output the information from the controller to the user in whatever format the user deems “right” (keeping in mind that the template doesn’t necessarily have to output HTML). Some go as far as to abuse it to do more controller-esque queries and that’s unfortunate. The template language is for you to lay out the information in such a way that the designer can easily re-structure / style it.
imo, it’s not the designer’s job to do the initial templating because you should be doing it whilst you’re Behaviour Driven Developing (BDD). You’re doing that, right?
**No built-in admin** will probably be available as a Rails engine around the time 3.0 comes out. I would be really surprised if nobody else had thought of this yet. Stay tuned on this one. Also: I don’t think it’s that huge an advantage over scaffolding / DIY.
Now on to what you **like** about Rails
**Directory structure** was something that made me go “omgyes” when I first started with Rails. After coming from the unstructured PHP lands, this was a Godsend. And yes, you can think of Gems like JARs.
**Dependency management** is greatly improved with the advent of Bundler. Given that you’re a new guy to Rails, you’re probably using 2.3 at this stage since that’s what `gem install` installs. Bundler gives you a greater flexibility for installing things from not only Rubygems, but from git repositories as well. Check it out if you get the time.
And that’s the end of your post and the end of my comment.
Thanks for an interesting insight. If there’s anything I can help you with just drop me an email at radarlistener@gmail.com
There’s also another method calling method, and in my opinion this one is a godsend for code brevity and readability. for example, you want to return all the comments on all of your bog posts you can either do
Post.all.each { |p| p.cmments }
or, my preferred way
Post.all.map(&:comments)
On the other side of the “schema” fence, I’d say having the schema in the model is useful because you don’t have to look at the database to remember what fields are in table that the model represents. You could certainly comment the model with the fields, but at that point, you might as well just define the schema in place.
I use the annotate gem for this (http://github.com/nofxx/annotate). It adds the schema information as a comment block at the bottom of your models and unit tests, and can also add the output of `rake routes` to your routes.rb file if you like.
I’ve been using Django for a few years now, and I’ve never really seen a reason to try Rails. I don’t think I am going to try it either. At least not in the near future. This blog post pretty much confirmed what I thought: Rails is a living hype. Thanks!
Rails is a 4-year hype. Right.
im glad that (1) some admin plugin and (2) datamapper – ruby’s first class ORM – have been mentioned.
you should have a look at haml and sass as well, the will make html and css half the pain (or less). especially python people should like it, it has meaningful indentation! (in case of haml i love meaningful indentation, for programming not really)
i think django’s ORM is forcing me to do things in ways that seems overly verbose.
regarding the syntax comparison i would be interested which you like are using both for a couple of months. i prefer ruby now any day (which i didn’t at first). no more “foo(self)” or “__str__ and str(foo)” or worse “__init__”.
and blocks? they became as vital to my code as breathing to my life.
I agree on __init__ and self: they are warts in an otherwise very pretty language.
Regarding directory structure and dependency management in Django, check out this post
http://blog.zacharyvoase.com/2010/02/03/django-project-conventions/
Virtualenv + PIP with a requirements file can get close to Ruby’s gem, but that is still something I envy from Ruby.
[...] Thoughts about Rails from a Django guy – Shizzle – Lenni sips from the rails koolaid and gives his impressions. (He's a django/python guy) [...]
> multiple possible function/method calling syntaxes
I really thought that was a myth.
I’m a new Python programmer coming from a Perl background, and I hope I never will be worried for this kind of stuff.
Anyway, interesting article. I’m always wondering if RoR is worth it, but I never have the time to try it…
Hey,
Thanks for sharing your impression. I hope we all do understand that when trying a new language it’s difficult to stay objective – we all have our likes and dislikes, like, for instance, your dislike of sigils. Also, some things are just too complex to really master in short period of time, for instance, after three years of using ActiveRecord I can say I can handle a DB of any complexity with it.
The schema is different from models because ActiveRecord provides things on top of a traditional relational DB like polymorphic associations and single table inheritance.
Also, Rails is more than just Rails. Rails now is a big ecosystem of plugins and libraries. For instance, most Rails devs I know have switched to HAML from ERB, and this is a big win.
Like Mladen, I was pleasantly surprised with this article. Most people who write about experimenting with “rival” tools (like Ruby and Rails are to Python and Django) tend to either brace their own traditions and treat anything different with hostility, or start the experiment actually wanting it to fail, just to confirm their preferred tool is better. You kept an open mind, and your post is very unbiased. Nice work!
I’m going the other way around (experienced Rails developer learning Django now, though I’ve known Python longer than Ruby), yet I agree with many of your points.
Separation of schema and model brings all kinds of warts to AR (like making it pretty hard to take advantage of foreign key support in the data base, or making AR incredibly unreliable when dealing with multiple RDBMSs as metadata is lost every time you recreate your schema). I disagree with Ryan Bigg’s comment, table definition is not some “crap”. In fact, having a single line of type/domain definition for each column is often more compact than having multiple lines of “validates_*_of” for all the trivial validations Rails forces me to write.
As for templating, I agree you shouldn’t include complex logic in templates, but in my experience it’s easy to keep templates simple and fairly readable with Rails. Not only because you’re encouraged to keep everything on its place (like helpers), but Ruby is a far better fit for a templating language than most other general-purpose languages (mostly due to blocks), and even than many template-specific languages (which are often so constrained or rudimentary that you’re forced to write tons of helpers to achieve things that are very simple with Ruby). Anyway, you might want to have a look at Haml.
Forgot to say: migrations are incredibly useful for non-trivial cases. For trivial ones (like adding/removing a column or table), though, I agree it can be an annoyance. Some form of automatic migration should be supported. Also, something you probably didn’t experience, but they have an abstraction flaw in that they’re naturally tied to a specific source code revision, but Rails will always run them in your working copy. This might bring you problems under rather specific circumstances, but fortunately this is easy to work around when needed (and I really don’t know how this could be made any better).
I have tried rails and django, and I must say that I feel somewhat inadequate in that I haven’t been able to master rails yet. My try with django was more successful. I remember that the experience was more of my liking.
Reading your entry, now I realized that my biggest problem with rails >>was<< Active record. So now I know that there are some alternatives, and I may give it a try again.
I have learned ruby, and it is a very enjoyable language to write scripts in. You are right that there is some confusion with the sigils at first, but once you learn what they mean, it actually helps to make the code much smaller and easier to understand.
You must compare django to pylons – sometime. Thanks.
For dependency management we use VirtualEnv, Pip, and a Requirements.py file, you can specify specific versions, or even link to the exact tarball you want it to download and install. Setting up a new dev vm is a simple as:
mkvirtualenv myproject
pip install -r requirements.py
python manage.py runserver
http://github.com/kbjr/node.js-MVC
No, but this is. I have no idea if it is any good, but my point is nowadays if a language can be used for the web, it’s extremely likely that there will be an MVC framework for it.
Migrations might seem inconvenient, but they are a useful layer of indirection. It allows your database schema to evolve more easily than is possible by having your schema inferred from model code. I use both Django and Rails extensively, and one of my biggest annoyances with Django is the lack of (official) schema migration tools.
While not “official”, Django users that find they need a smooth way to handle db migrations should look at South: http://south.aeracode.org/
I think this was a fair article. For just 2 weeks you understood the gist of it.
Yep, ActiveRecord is something that, if you come from another ORM, will bother at first. Then it will grow on you pretty fast. The problem is always the previous baseline comparison. The Migration part is actually much clever that it seems. You decouple the database maintenance from the model, and it shows. Being closer to SQL is also a good thing. I prefer not having too much magic on the mapping side and AR is pretty straightforward in this regard. As many already pointed out, you can easily use DataMapper or Sequel if you want (though most of the time I think they are not necessary). Then you have NoSQL databases nowadays, and you will drop AR for MongoMapper or MongoID or CouchRest anyways
I don’t really feel the need for an Admin in Rails. And it seems like the community feels the same because there were many attempts to make an Admin and none became really famous. So the conclusion is that the majority of use cases for Rails just don’t need it.
I also don’t think having Ruby directly in the templates is a bad thing in itself. It wasn’t bad in PHP or JSP as well. The problem is always the bad developer that decides to put everything in it. When this happens I don’t think that the tool has to be locked down, but the bad developer is the one who should leave. But, if you really need 100% Ruby free templates, you have great options such as Haml and Sass. You really should check them out (they even follow Python’s indentation, so you should feel right at home
There really is a dependency annoyance in Ruby/Rails, which was greatly simplified with the use of Bundler. I strongly recommend you take a look at gembundler.com. Than the dependency problem will become virtually non-existant as well.
You also need to take a look at the rest of the Ecosystem. Rails, by itself, is just the foundation for the rest of the community. It grows exponentially in power when you start using what the community has provided. RSpec and Cucumber + Webrat or Capybara + Factory Girl or Machinist + Metric Fu are a very very strong testing foundation. Then you can hook it up to Hudson or Cruise very easily. To deploy to production I strongly recommend you try Heroku.com. But if you want to build your own machine from scratch, Phusion Passenger will make it trivial.
Then you several gems/plugins such as Inherited Resources, Devise, Will Paginate, CarrierWare, Acts as Solr Reloaded, Thinking Sphinx, Formtastic, Twitter Stream, exception notifier, pdf-kit, admin_data, Resque or Delayed Job, CanCan, Acts as Taggable on Steroids, Whenever, AASM, etc. Check out http://ruby-toolbox.com for more goodies.
I hope you want to keep on with your pet project. Please try to explore those other projects and you will find out why Rails is so powerful as the foundation for this vast ecosystem.
You don’t need to go so far to find something great for simplifying web development. I looked at Rails too, but ended up investing my time in web2py, and am very happy I did. Django innovates more than rails, web2py innovates more than Django. Simple as that.
Nice post -
I like Django too. I do not have a programming background and took on Django. After quiting in frustration (I installed it on a windows machine initially) more than once – I made a change and installed ubuntu. It was like the gates on heaven opened up. Now I can hold my own – however I can see I have a lot to learn.
Great post! I’m the exact opposite of you: Love Ruby, like Rails, appreciate things about Django, don’t feel comfortable with Python at all.
I think you hit on some of the big differences, but one of the things I think most Django folks don’t pick up on immediately is the “pluggable” nature of Rails.
There are a kazillion plugins and gems out there that can make Rails do what you want it to do.
* Don’t like erb? Use liquid, which is basically an exact rewrite of the Django template language — with all its fun and flaws.
* Don’t like AR? Use Datamapper. You can hack it in now, but as of Rails 3 (which, frankly, we should start calling Djrails) you’ll be able to swap in any ORM you want pretty much effortlessly.
And so on.
The one piece of this I have not seen is an admin like Django’s. There are some out there, but nothing with that Wilson Minor touch, if you know what I mean.
The one project I’ll steer you to is Formtastic, which is an absolutely brilliant DSL for making forms easier to do. It’s really clever. You’ll still end up building forms for your admin, but the productivity lost there is more than gained when you have to do the same for your public-facing pages — which Django does nothing to help you along as far as I know.
On migrations, I would suggest spending a little more time with them. They are insanely useful. This is the Django admin for Rails: There are Django workalikes (sorta), but Rails migrations are one of the killer features I miss the most in Django.
Lastly, I think you missed the biggest Django advantage over Rails: pluggable applications, which is awesome. Rails 3 is supposed to have something like it, but to my mind this is the biggest killer feature of Django.
Nice post, and keep it up.
I tested ruby and djagno. Ruby is very strange language – i select python.
I’ve installed and played around with Django once or twice, but I’m definitely a Rails and CakePHP guy for the time being. Of the two, I definitely prefer Rails – if for nothing else than the beautiful Ruby syntax. After working with CakePHP (my day-job), I appreciate Rails a whole lot more.
But honestly, the thing I like most about Rails is the amazing community. In particular, http://railscasts.com/, which is (in my opinion) the corner stone of the Rails community. I think if Django or CakePHP had something like Railscasts I’d be a lot happier to use them.