In the Rails world, the layer which generates the final markup sent to the browser is called the View layer. In a Rails View, you can chuck as much rails code as you like in amongst your markup.
Some of the early sites I worked on many years ago were written in PHP, which had the same idea.
Um. . . Sure, you can put any logic you want in a Rails template, but people don't. Rails applications tend to have a nice separation of layout and application logic. Django really likes to constrain users here - not even letting them use a full "if" statement. It's really unfair to just say Rails == Unmaintainable PHP. PHP often becomes that way because there is no immediate way of separating the code. Smarty and others can force you, but both Rails and Django put a really obvious place to put your app logic and developers tend to respect that. Part of this is just how much rope do you give a developer and it's fair to say that one shouldn't give developers that much leeway. However, it's wrong to just equate the two.
Multiple Apps in a Project
Really, neither framework (or any code) is as pluggable into random situations as we programmers would like. The author suggests that you can use models from different applications in Django. That sounds cooler than it is. They're all running off the same database and in the same project. Really, what Rails creates are projects in Django-speak. And the "apps" convention in Django doesn't help you in development. It helps in organization sometimes - especially the admin interface - but it isn't some spectacular thing where you can just reuse random code in a way that you can't with Rails. Well, I take that back, there is one way that is really nice: namespacing. You can have a blog app that has an Entry and Category model without having to name it BlogEntry and BlogCategory because it would conflict with your Category model for, say, a real estate part of your app. And that is helpful in a way that Rails doesn't solve nicely. However, for the most part Rails and Django provide decently equal utility in this area, they just name the things differently.
URL Routing
Django's routing is really verbose. You have to specify each route you want. Rails has a bunch of shortcuts for common cases (REST as well as :controller/:action/:id). In a way, this is just the explicit vs. implicit thing. Django makes you explicitly state your URLs while Rails will let you state them, but you don't have to should you like the defaults. The Django folk say that it takes very little time to write routes (true) and that one should be thoughtful when making URLs (also true). But sometimes it just feels tedious. Really, it's just a matter of preference.
Ruby (Perl’s Ugly Sister)
This is kinda low at some points (why I went to it last - I don't like dwelling on such poor arguments). Ruby doesn't actually use that many symbols ala Perl. All variables are done without symbols; I think strings built as "#{var} is cool" are easier to understand than "%(var)s is cool" % {'var': var}. And it isn't like Python doesn't have weird things like "/".join(list).
Really, my beef with Ruby would be how easy (and common) it is to add methods to ancestors without really making it clear. As you start adding methods to Object, you can get yourself into a position where Python's explicitness is really nice. However, when you want to get something done, Ruby can be nice in that respect. It's like having a circular saw: really good for both cutting wood and cutting your hand off. Likewise, Python's mixins are put onto attributes of the model - so that you have things like house.photo.url rather than house.photo_url (although Django did create the second for a long time). That makes it very clear what you're adding while if you say "acts_as_nested_set" in Rails, you don't immediately see which methods are being added.
Ruby's problems aren't really syntactic, but it can have things that one could define as problems.
--
I've put out two sites in Django and one in Rails and at this point I'm developing two projects in Rails. The Django community is really smart and understated and I still read a lot (smart information translates well to anything), but Django just doesn't see the same pace of development that Rails does. Even something simple such as following reverse foreign keys isn't implemented in Django. Yep, if you try Entry.objects.all(select_related="comments") it will just silently fail (how's that for letting errors pass silently that shouldn't!). And it is difficult and Malcom has way more on his plate than any normal person could even conceive of, but. . . it's still missing.
And the Rails community has calmed down a bit, the Merb camp seems to be adding nicely to Rails 3, the Rails framework covers so many more edge cases than it used to as well as just seeming more reliable, and deployment has really stepped up with Passenger.
Django is a wonderful piece of software with great features and really smart, considerate people using it. It just isn't seeing as great a push toward little simplifications for more edge cases in the way that Rails has been. Frankly, they're so much alike in all the meaningful ways - I think that's why I have such an easy time wrapping my head around both.
"Django really likes to constrain users here - not even letting them use a full "if" statement."
Yes, but as you've noted it's for a good reason. This is really one of the few places where Django gets opinionated by default, and personally I'm OK with that; keeping people off the slippery slope of "well, I should write this in a cleaner way, but for now I'll just stuff some application logic in the template and fix it later" is a goal I can get behind.
"The author suggests that you can use models from different applications in Django. That sounds cooler than it is. They're all running off the same database and in the same project."
Not really. I can have multiple different Django "projects", each running its own settings, its own database, its own URL configuration, its own templates, etc., but all using the same single copy of an application module somewhere on the server. Last I checked this was non-trivial to do in Rails, while in Django it's made very easy since it's a common use case, and encourages neatly abstracting/encapsulating common pieces of functionality for reuse.
"The Django folk say that it takes very little time to write routes (true) and that one should be thoughtful when making URLs (also true). But sometimes it just feels tedious. Really, it's just a matter of preference."
Personally, I tend to view this more as a security concern than a programmer-convenience concern; if my framework is auto-mapping URLs to any code it can find, it may auto-map some things that I didn't want to expose (this was the source of an exploitable vulnerability in Rails a while back, as you may remember). If the framework only handles the URLs I tell it to handle, I don't get that situation.
Mostly, though, I like Django because it (and Python) fits my brain.
If people don't agree on the IF statement, they just don't agree on it. I find that I can discipline myself enough to use a full IF - having always used the pyif (http://www.djangosnippets.org/snippets/130/) template tag in Django. I don't think this is such a big deal since one can swap out the templating layer in both Django and Rails for something they'd rather. If anyone reading this sees this as a big point, Liquid in Rails offers a more Django-like experience and Cheetah will give you things like full IFs in Python.
You make a good point about not having to copy the code into the project directory and have multiple pieces of code sitting on the server. Someone pointed out that Rails Engines (included in 2.3) allow for this, but I haven't personally used them to know how nicely they work.
For the security concern of auto-routes, this is actually a bigger concern in Python than in Ruby just because of the different ways that they handle OO stuff. In Python, everything is a public method. So, if Django just mapped URLs to methods, there would be no way of hiding a method you didn't want called. Ruby has the ability to make private and protected methods and Rails only makes public methods available as actions (the private and protected ones still being able to be called in their scope).
So, it isn't a great security concern in Rails since it's trivial to define what is public and what isn't. Likewise, if one chooses, you can decide to map all of the URLs explicitly like Django and turn off the default :controller/:action/:id route. So, Rails offers both ways.
Just as a note about Python: Django could just auto-map URLs to any method not starting with an underscore (the convention used in Python to say, this is kinda private even though Python will let you use it). Or there could be a kwarg (keyword argument) in the method signature that Django looked at. Anyway, there are ways around the fact that the Python language doesn't have explicitly private methods. Django's convention (like Python's) is just that explicit is better.
"If people don't agree on the IF statement, they just don't agree on it."
Pretty much. And while individual cases can be argued, I think the general goal of keeping program logic out of templates is a good one.
"For the security concern of auto-routes, this is actually a bigger concern in Python than in Ruby just because of the different ways that they handle OO stuff. In Python, everything is a public method. So, if Django just mapped URLs to methods, there would be no way of hiding a method you didn't want called."
Actually, what I'm thinking of is a case where you might have a single application running on multiple sites, and -- for security reasons -- there'd be some views that you wouldn't want exposed on one or more of those sites. Forgetting to "un-map" even a single URL could lead to major problems (and, since an auto-mapping system can, in theory, locate anything that's on the import path, the risk seems to me to be a bit too much to accept just for the convenience of occasional automatic URLs).
"Yes, but as you've noted it's for a good reason. This is really one of the few places where Django gets opinionated by default, and personally I'm OK with that; keeping people off the slippery slope of "well, I should write this in a cleaner way, but for now I'll just stuff some application logic in the template and fix it later" is a goal I can get behind."
Pretty sure Rails, via some plugin, lets you easily use Liquid templating in place of erb. Likewise for Ramaze and Merb.
>Django's routing is really verbose. You have to specify each route you want. Rails has a bunch of shortcuts for common cases (REST as well as :controller/:action/:id). In a way, this is just the explicit vs. implicit thing. Django makes you explicitly state your URLs while Rails will let you state them, but you don't have to should you like the defaults. The Django folk say that it takes very little time to write routes (true) and that one should be thoughtful when making URLs (also true). But sometimes it just feels tedious. Really, it's just a matter of preference.
You've linked to the documentation about following foreign keys, not reverse foreign keys.
So, you have a blog with entries and comments on those entries. A Comment has a ForeignKey to an Entry. That's a normal setup. In Django, you can say Comment.objects.select_related("entry").get(id=5) and that will get you the comment with id 5 and its associated entry. However, you cannot say Entry.objects.select_related("comment_set").get(id=12) to get the blog entry id 12 with its associated comments.
There are a lot of people who use Django that don't realize this limitation exists because they haven't gotten that deep in their usage of the framework.
On a personal note, in the future I would appreciate it if you didn't attack my truthfulness with statements like "Not much you say about Django is very accurate, actually."
Some of the early sites I worked on many years ago were written in PHP, which had the same idea.
Um. . . Sure, you can put any logic you want in a Rails template, but people don't. Rails applications tend to have a nice separation of layout and application logic. Django really likes to constrain users here - not even letting them use a full "if" statement. It's really unfair to just say Rails == Unmaintainable PHP. PHP often becomes that way because there is no immediate way of separating the code. Smarty and others can force you, but both Rails and Django put a really obvious place to put your app logic and developers tend to respect that. Part of this is just how much rope do you give a developer and it's fair to say that one shouldn't give developers that much leeway. However, it's wrong to just equate the two.
Multiple Apps in a Project
Really, neither framework (or any code) is as pluggable into random situations as we programmers would like. The author suggests that you can use models from different applications in Django. That sounds cooler than it is. They're all running off the same database and in the same project. Really, what Rails creates are projects in Django-speak. And the "apps" convention in Django doesn't help you in development. It helps in organization sometimes - especially the admin interface - but it isn't some spectacular thing where you can just reuse random code in a way that you can't with Rails. Well, I take that back, there is one way that is really nice: namespacing. You can have a blog app that has an Entry and Category model without having to name it BlogEntry and BlogCategory because it would conflict with your Category model for, say, a real estate part of your app. And that is helpful in a way that Rails doesn't solve nicely. However, for the most part Rails and Django provide decently equal utility in this area, they just name the things differently.
URL Routing
Django's routing is really verbose. You have to specify each route you want. Rails has a bunch of shortcuts for common cases (REST as well as :controller/:action/:id). In a way, this is just the explicit vs. implicit thing. Django makes you explicitly state your URLs while Rails will let you state them, but you don't have to should you like the defaults. The Django folk say that it takes very little time to write routes (true) and that one should be thoughtful when making URLs (also true). But sometimes it just feels tedious. Really, it's just a matter of preference.
Ruby (Perl’s Ugly Sister)
This is kinda low at some points (why I went to it last - I don't like dwelling on such poor arguments). Ruby doesn't actually use that many symbols ala Perl. All variables are done without symbols; I think strings built as "#{var} is cool" are easier to understand than "%(var)s is cool" % {'var': var}. And it isn't like Python doesn't have weird things like "/".join(list).
Really, my beef with Ruby would be how easy (and common) it is to add methods to ancestors without really making it clear. As you start adding methods to Object, you can get yourself into a position where Python's explicitness is really nice. However, when you want to get something done, Ruby can be nice in that respect. It's like having a circular saw: really good for both cutting wood and cutting your hand off. Likewise, Python's mixins are put onto attributes of the model - so that you have things like house.photo.url rather than house.photo_url (although Django did create the second for a long time). That makes it very clear what you're adding while if you say "acts_as_nested_set" in Rails, you don't immediately see which methods are being added.
Ruby's problems aren't really syntactic, but it can have things that one could define as problems.
--
I've put out two sites in Django and one in Rails and at this point I'm developing two projects in Rails. The Django community is really smart and understated and I still read a lot (smart information translates well to anything), but Django just doesn't see the same pace of development that Rails does. Even something simple such as following reverse foreign keys isn't implemented in Django. Yep, if you try Entry.objects.all(select_related="comments") it will just silently fail (how's that for letting errors pass silently that shouldn't!). And it is difficult and Malcom has way more on his plate than any normal person could even conceive of, but. . . it's still missing.
And the Rails community has calmed down a bit, the Merb camp seems to be adding nicely to Rails 3, the Rails framework covers so many more edge cases than it used to as well as just seeming more reliable, and deployment has really stepped up with Passenger.
Django is a wonderful piece of software with great features and really smart, considerate people using it. It just isn't seeing as great a push toward little simplifications for more edge cases in the way that Rails has been. Frankly, they're so much alike in all the meaningful ways - I think that's why I have such an easy time wrapping my head around both.
Eh, I have to get dinner.