In terms of feature and ecosystem surface, there is one area where I think Django is a clear winner: Django Admin. It is a very mature part of the framework and there is a large ecosystem around it. Compared to how useful that is for standing up an MVP SaaS (especially in anything remotely enterprisey), I would find it difficult to consider Rails if I ever envisioned needing admin.
For what it's worth though, I think that Django and Rails are both exceptional choices and in terms of ergonomics, best in class. I wouldn't have complaints about the framework to coming into a project using either one.
I thought Django Admin was cool when I first set it up, but as soon as I hit a few of the issues the parent mentioned, Admin broke or became irrelevant.
It's super weird because Rails is known for convention over configuration and includes default packages for basically everything you might need EXCEPT auth and admin. Meanwhile Django removes a lot of the magic of Rails and lets you do it yourself, except for bundling auth and admin into the core product.
I have found that at least for my users, admin type functionality and views generally require a lot of custom work that is not easily turned into convention. About 4 years ago I stopped using Active Admin completely and just started using Ransack + Kaminari gems on their own. I have been a much happier with the way that pattern has worked out.
Rails has its downsides (helloooooo memory usage!) but for getting up and running fast and having a full toolkit available to get the basics done, it's a pretty amazing project.
The downside of SQLAlchemy is that it's less pleasant to use for simpler queries/tasks, so which ORM is better depends on the project. I've worked on codebases that never crossed that threshold, and ActiveRecord gave a consistently great developer experience. YMMV.
For people getting started with engineering, AR is a nice wrapping/mapping of SQL => object oriented models. There's a mix of productivity, approachability, and feature set that puts AR ahead, for me, as a general use ORM.
I would agree, though, with a strong and experienced engineering team Ecto and Elixir are quite nice.
Maybe it's morphed into a more general ORM in the 10+ years since I've touched it, but the active record pattern breaks down very quickly once you get beyond basic CRUD apps.
* Django has comparatively limited I18n and localization faculties compared to Rails (with Django’s i18n built atop gettext, which I always found kind of brittle with .po files/string-based keys)
* No intelligent/efficient class reloading in development. The whole development server just restarts when you make changes
* No reloader for the shell (horrible for developer ergonomics - you can't just type "reload!", you have to restart the shell to pull in any change)
* Caching faculties in Django are much more limited - no template digests (to make template fragment caching much more robust)
* ActiveSupport has also always been a god-send for productivity. It may seem small but things like “Array#to_sentence” and the time functions (i.e. 1.day.ago) are incredibly useful.
* No default assumption of multiple environments (no default development/testing/production configuration files, environment detection, etc). This is pretty ridiculous for a web application framework.
* No built in credential encryption (makes keeping a team in-sync with keys for integrations a comparative pain)
* Dependency management is much more challenging in Python. The de-facto virtualenv + requirements.txt combo is lossy (no dependency graph) and awkward compared to bundler. There are other solutions here but something so foundational shouldn’t be so hard.
Django was the first web application framework I learned and I still work with it professionally from time to time (as recently as ~2 months ago). I am just a bit stunned by how much it has fallen behind in terms of its broad state of maturity, community/ecosystem, productivity, etc.
I don't quite share the same experience with i18n though. I always found Django statical code analysis to extract translation keys to be superior in many ways to other translation systems. It is giving useful context that are stored in the PO files and good translation tools use them. I also never had any issue with string based keys. You can chose an english based key or an abstract whatever you prefer.
Some of the annoyance you mentioned, that I agree completely, are more of a language issue like: reloader, or dependency management.
For multiple environments there is a very simple pattern you can put in place using an environment variable and conditional imports. something like:
from settings.base import *
if env == 'prod':
from settings.prod import *Take a look at this dated doc for zope 4 - anyone who's had to fight with bundler should see some similarities - good and bad i think:
https://docs.plone.org/4/en/old-reference-manuals/buildout/b...
You can still use it today, too (but you probably don't want to):
ActiveRecord was also surprisingly slick. I'd previously mostly used Doctrine and over the years I've mostly come to dislike it. AR was fine though and had some features I liked quite a bit. Scopes are really neat. Like any ORM though there are plenty of double edged swords all over.
I'm actually keen to work with Ruby more since working on that project. Rails is really nice, even if it's a lot different from how I'm used to working. It felt very productive.
This means a lot of interesting engineering work and optimizations are out of your hands. Some people think that's a bad thing, I think it's a great thing. Depends on your goals.
That being said, I am not a Ruby developer, I am a Python developer, so I'll try to address these points as best I can from the other side of the equation.
* Authentication - this is fairly simple to address. It's a fairly easy-to-use pluggable backend. It's not very hard to write a system to replace the default which would let you log in using other credentials. Also, a few years ago you couldn't replace the default User model - that has since been changed.
* Asset pipeline - fair point, but I prefer to keep my assets separate from the backend if possible - my current work project has a backend API in django with a separate frontend repo with all the JS/CSS
* Configuration - the best solution for this I've found is django-environ[0]. Alternatively, the built-in `DJANGO_SETTINGS_FILE` environment variable lets you specify a different base config file.
* Sidekiq/Celery - The API, I'll give you, however it's fairly easy to configure Celery to use Redis
* Mailer previews - I've used mailhog[1] before. This gives you a local mailbox to test with and will be closer to your final configuration anyway.
* Better security - possibly by default, but I haven't had any issues with django-rest-framework in the past
* Testing - pytest with pytest-django is also great to work with.
* Django ORM vs ActiveRecord - I don't have a ton of experience with ActiveRecord but I like the Django ORM. There's also SQLAlchemy, but it's a bit odd to rip that out of django if you don't need to.
I like Django because it's solid out of the box, but still provides a way to extend the core to be as flexible as you want. I assume it's possible to do this with Rails, but that's not my area of expertise.
I do appreciate you outlining things you like better as opposed to just saying "Django is terrible". I'll definitely have to try Rails again and see what I think of it now.
if you don't have complicated statistical/machine learning needs, i'd recommend ruby on rails every time. it's so fast to get started and productive. and the language is performant enough to get you to initial success (at which point you can choose to spend money to attain greater performance).
It is a huge mountain of work you have ahead yourself if you are a newbie in both domains.
Sure you might be able to slap together a simple CRUD app following a tutorial but truly knowing what you are doing will take months, if not years. It is a huge investment.
When I first came across Ruby -- and particular Rails -- I loathed it. Ruby's syntax allows you to get pretty creative, and jumping into Rails + Rspec is like jumping into a Perl repo that's been managed by 3 different people over ten years. There's all kind of things that -- because the syntax is so loose -- it's not clear what's going on. It doesn't help (in my opinion) that Ruby's own style guide almost encourages this: dropping the "()" from functions that take no arguments; Eiminating "{}" around certain hashes passed into functions; The "!" marker having a seemingly different meaning in almost every library, etc...
When you're new to Rails and Rspec, it's easy to have no idea what's going on.
That being said, you can prototype an entire business in a few days Rails. It is that easy. It's incredibly polished. It's opinionated in mostly right ways, and all of its libraries are, too -- which means you don't often find people doing crazy shit (except Devise, everyone is always doing something crazy with Devise).
As much as I hated Rspec with a passion, I do feel like it's the best testing frameworks I've ever come across. It lets you be SUPER expressive about what you're testing.
I go against the Ruby & Rspec style guides on a few things, but I feel like no other combination let's you write code that's so expressive.
And, finally, anything you want to do in Rails has a library built in that does it very well. And unlike in -- say JavaScript for example -- there aren't ten libraries to pick from. There is a clear winner, and I think that's good for the community.
Also, almost every major API you can imagine has a Rails Gem so that it plays nicely with the framework.
Don't get me wrong, I loved Django and I still think it's a great framework. My love for Python, Elixir, and Kotlin are strong.
Ruby & Rails are by no means perfect, but I do feel like it's a very clear winner if you're starting a new web business. The number of companies I've seen flounder because they wanted an App + a website + (obviously) backend business logic... and all of that in one language, in one code base -- it's impressive. I've seen a lot of Rails businesses fail. But despite what people warn about scaling, I've never seen a Rails-based company fail because of Rails. Plenty have flourished -- Shoppify, GitHub, AirBNB, etc...
I could go on and on about the advantages WRT hiring, too. Don't even get me started...
Seems like this describes any app in any language I’ve ever worked on. Certainly Rails apps are more prone to this phenomenon because of the low barrier entry. Having worked with apps that have grown from Rails 2 through 5 (and soon 6) it’s quite possible to build Rails apps that “age well”.
Case in point for a Rails app that can age well is GitHub. When they launched in 2008 they were probably using Rails 2.0.2 (best guess based on release notes).
I am only familiar with Django and Rails, can't comment about Laravel.
If you are building a basic CRUD app, definitely stick with Rails. If you are doing some kind of CMS or need machine learning pipeline, go with Python.
A warning about Ruby/Rails: some folks have moved on to shinier languages/frameworks and as a result there are lots of unmaintained gems (gems are 3rd party libraries in the Ruby world) out there. For instance, I needed a curl wrapper written in Ruby. Nothing worked for me so I ended up forking Ethon [0]. I am hesitant to send PRs, since I doubt that they will get merged. Now I am maintaining two codebases at once. I will probably rewrite it from scratch at some time.
A warning about Python/Django: dependency management is kind of a mess [1]. See linked discussions [2][3][4][5].
[0] https://github.com/typhoeus/ethon
[1] https://xkcd.com/1987/ (Add pipenv and poetry to the mix)
[2] https://news.ycombinator.com/item?id=20672436
[3] https://news.ycombinator.com/item?id=18612590
Curious, why didn't something like faraday worked for you?
2. Nothing is stopping you from using multiple files for config. We use a config module with a separate file for DB, caching, DRF and etc.
3. Testing with pytest is pretty nice too.
Django rest framework is what makes Django great these days.
That said, everything is easy once you know how to do it. If this was the first time you've done this or there was research involved, it definitely makes sense that it would take longer!
I'm mostly asking bc I'm curious if you came upon a level of complexity that I simply haven't encountered.
Your complaints are valid from a subjective perspective, but if your bar for something being "a pain" is really "took longer than 10 minutes", I can't imagine how you function as a software engineer as even in Rails there are many things that will take longer to do.
That's when I decided to pick up Rails tutorial and it was probably one of the best tech-related decisions I made in my businesses.
I shouldn't use cookiecutter templates, plugins, scripts to make working with the software tolerable. It should just work and get out of my way. Well, at least when doing a greenfield development.
Take a look: https://rubyonrails.org/doctrine/
In comparison, I too could waste my entire weekend tinkering with something in Rails, but I instead choose to do things the right way and look up a tutorial to explain how to do it easily, which it sounds like you did with Rails. Why you didn't do this with Django instead of wasting weeks, I dunno.
Again, if you prefer rails for subjective reasons that's fine. But blaming Django for being "too much of a pain" just because it sounds like you chose to do things the difficult way is pretty unfair.
Every Django thread on HN usually involves a healthy amount of discussion about the pros/cons of Django, and it's really helpful. You would expect that Rails threads have a discussion about the pros/cons of Rails, right? Except instead, every Rails thread also turns into a discussion about the pros/cons of Django.
If Rails is so good then why do its users feel they have to constantly defend itself against non-existent attackers?
Ironically, the OP you're replying to is much more substantive than your own attack.
So if you are ever in a position to pick between Django and Rails for CRUD-y SaaS app, go with Rails. You can't go wrong with that.
I have seen both sides of it, that's why I decided to vent it out.
P.S. Don't get me wrong, I have tons of respect for people doing open source and don't want to badmouth Django folks. But in my limited experience, it just wasn't a great experience.
Not everybody is an expert on both, so it's nice to see concrete lists like the one posted above.
I think it boils down to people only being experts in Rails and fearful of having to change to other tech.
I used to get the same kind of answer when comparing Rails to other tech such as Node or Sinatra.
I've got my complaints about Devise, but I'll take those pains any day of the week over the alternative nightmare of "built in-house" authentication.
At this point, if somebody doesn't want to use Devise in a project I'm working on, they better have a _really_ good explanation. To me, it's like suggesting setting the building on fire.
There are very legitimate reasons why your SaaS app might want a nuanced workflow for these things.
It's pretty effortless to override and/or completely rewrite the views/flow with something like Devise.
Every time I've ended up in this scenario I've wished that I had just built from scratch in the first place.
You have a multi-tenant SaaS application that needs to support the following:
* Accounts may have different password, lockout, and expiration policies.
* There's a generic "login" button on the marketing site that 50%+ of our users use. This generic login page must implement all account specific constraints (probably via a 2-step login form)
* Some customers have SSO. For some customers, using SSO is optional. For others, it is required.
* Owners of accounts have a limited impersonation feature that allows them to see only certain parts of information in eyes of one of their account members
I've had to do that with Devise. It was easy enough to fork the `devise-security` plugin and modify the configuration settings to handle lambdas. The lambdas were then set to pull the config values from the user's account configuration.
* There's a generic "login" button on the marketing site that 50%+ of our users use. This generic login page must implement all account specific constraints (probably via a 2-step login form)
That's super easy.
* Some customers have SSO. For some customers, using SSO is optional. For others, it is required.
I'm in the process of adding exactly this to my project's Devise configuration right now. It's a little tricky, but only because our previous attempt at SSO was very strangely done (and I now understand why so many users complained about not being able to log in).
* Owners of accounts have a limited impersonation feature that allows them to see only certain parts of information in eyes of one of their account members
User permissions are outside the scope of Devise, since it just handles authentication. But the Pretender plugin makes user impersonation dead simple.
I’d love to see more pushback from devs on this. So many products nowadays provide an “experience” for auth which makes things unnecessarily difficult. Not showing login and password fields on a single page, ambiguous 3rd party auth rules, weird account linking logic, etc.
If I were to bring in 3rd party gem for auth, I'd have gone with Sorcery rather than Devise.
> You just have to be cognizant of what you're doing
These two ideas are incompatible with each other.
You don't roll your own security. You just don't do it. There are far too many variables that you can screw up, and anything you come up with isn't realistically going to go through nearly as much battle-testing as a ready-made solution (either upfront or on an ongoing basis).
> Custom built auth isn't as scary as you make it to be
Custom-built auth should be scary. Anyone who's worked on the security story for a popular framework will tell you that.
If you're not scared by it I'd have to assume you're either not seeing large swathes of the problem space or you're a genius.
Don't write your own crypto. That's great advice. The idea that everyone's auth needs are so standard they fit for every app just hasn't been realistic in my experience.
Yes, you don't roll your own security. You use powerful primitives provided by Ruby and Rails, such as bcrypt, has_secure_password/has_secure_token, encrypted sessions, secure httponly cookies with prefixes + samesite attrbiute all served over TLS 1.2+, with HSTS and CSP
But those are things that people normally delegate to either libraries (crypto) or the framework itself (session handling).
Of course, there's lots of places one can screw up, such as sending non-expirable password reset tokens, revealing private information and membership status via F2A/reset tokens. But those are the kinds of screw-ups that can happen in other parts of the website too.
That said, Devise is one of the few things that I don't completely dislike about Rails.
It's not so hard, you just define a custom user class -- plenty of SO snippets if you're lazy. Though I agree that it would be better if common user schemes like email login were supported out of the box.
>* Better security by default: Rails comes pre-configured with a bunch of security headers[0].
Django has security headers also https://docs.djangoproject.com/en/2.2/topics/security/
> * Sidekiq has a better API compared to Celery. Also, Celery's default broker is RabbitMQ, not Redis. It is really hard to find managed RabbitMQ hosting, for Redis there are plenty
There are several on Heroku, including with free plans. https://elements.heroku.com/addons/cloudamqp . I agree that Celery has a bit of a learning curve (e.g. heartbeat, concurrency, etc.). The project is improving, and python overall is getting better at async.
> Django, which is big on backwards compatibility.
Version 2.0 breaks code from 1.11, which happened in 2017.
> I decided to switch to Rails and haven't looked back
Maybe Django improved since you last looked, and could merit another try :).
> I don't want to start a flame war
Nor do I. Both cake and pie are good. The ability to weave in the rest of the python ecosystem (e.g. pandas, keras) makes Django attractive to me for many projects.
(I've shipped Rails applications and would probably not myself ever pick Django for a new project. Obviously, I do more security work than application development work).
When I started with Rails I was so frustrated with ActiveRecord that I develop some of the Django QuerySet API as a gem[0].
Rails does a lot of things right, but ActiveJob and everything built upon it (including the abuse of Redis) is a travesty.
The entire concept of serialising code and re-evaluating it (which is what these libraries do) is a joke.
Your job payload should be pure data but Rails ensures that it is code.
And you should builds the workers that consume it.
Doesn't sound right to me. ActiveJob just serializes the arguments to the job. The job runners spins up the rails environment (i.e. the code) and deserialize the arguments before executing the job.
There is no code serialization as far as I can tell.
I don't want to start a flame war here, but I think Rails (and gem ecosystem in general) is a better choice than Django, at least for SaaS apps.
These are all my personal opinions, take it with a grain of salt. Having said that, here we go:
* Authentication - it is a pain if you'd like to deviate from the standard Django User model (using username to login instead of an email). I don't like Devise either.
* Asset pipeline, even though it is not updated anymore (sprockets) and partially replaced by the webpacker, is still better in Rails
* Configuration spread across multiple files, by environment, instead of a single config.py file
* Sidekiq has a better API compared to Celery. Also, Celery's default broker is RabbitMQ, not Redis. It is really hard to find managed RabbitMQ hosting, for Redis there are plenty
* Mailer previews, small but quite useful utility
* Better security by default: Rails comes pre-configured with a bunch of security headers[0].
* Testing - Minitest and Capybara is just a joy to work with.
* I prefer ActiveRecord over Django ORM
* Rails isn't afraid to deprecate things and move forward. This isn't the case with Django, which is big on backwards compatibility. I don't like it, since it puts into a disadvantage folks who are starting new projects. Different strokes for different folks, I suppose
I could go on and on, but I remember struggling a lot with Django/Celery when building a SaaS app. I decided to switch to Rails and haven't looked back (Rails has its warts as well). YMMV
[0] https://guides.rubyonrails.org/security.html#default-headers
EDIT: Added last point about backwards compatibility