This is what got me started writing this post:
In the Rails world, we are holding up the DRY principle high. One outcome of this is that people do put stuff that has to be done for many applications into gems, to be reused. Authentication is such a case, as you need authenticaton for nearly every web application you write. And devise seems to be the most mature and poplular solution in this regard. Yet I decided to roll my own authentication for my latest project. Why?
Well, first of all, I am trying to get rid of all external dependencies, wherever possible. In my last project, we used 161 (!!!) gems. It was not a crazily complex project, just a regular, larger web application. But each and every gem has to be added to the load path, slowing down each and every require statement throughout the application. The led to server startup times of 15 seconds and above, depending on the machine. To make things worse, this time was needed for every launch of the Rails console, for every single isolated test you would run. That is just too much wrench in the works for me, so I absolutely wanted to avoid this in my new project. So, no dependency if I do not absolutely need it.
The next point, however, is simple "graspability". We all know source code is read far more often than written, so it should be easy for fellow developers to grasp what is going on. And although I like the devise source code, it is harder to grasp than code in your own application. First of all, people have to run
bundle open devise to take look at the source. This is not really hard, but it is another obstacle. Next, the devise code is far more abstract than your own code. You can name your user model
User, but you could also name it
ChemistryTeacher. The same is true for your Controllers. Devise can handle that, which is great! But this flexibility comes at a price, and that is the brainpower needed to understand how the code works. This problem becomes worse, as soon as you want to change some of the behaviour. Instead of just writing or adjusting the tests and implementing your code, you must go to great lengths to to find out how to hook into the existing gem code from your application. And the result? Not very satisfying. Some of the behaviour is defined in the gem, some in your application. Scattered in two places. Making graspability even harder.
My last point of criticism is bloat. Devise is very powerful, and certainly offers stuff I do not need. I just want session management and password reset. Yet the code for all the other stuff devise has to offer is loaded into memory when I require the gem. While this is negligible for a single gem, memory consumption becomes insanely high for each Rails process when you are using 161 gems.
Luckily, Rails 3.1 was out when I started on the new project, and this version introduced the
has_secure_password method in
ActiveModel. When I saw this in Ryan Bates Railscast, it immediately clicked. For me, that is the least common denominator, the one thing that is the same for each and every application. I do not need a gem to define my controllers, because I will want to change their behaviour anyway, at some point of time. But what
has_secure_password does, that is the one thing I will need anywhere.
So I just ditched every authentication gem out there and just went to write my own authenticaton. The process was smooth and easy, and in about a day of purely test driven development, I had a nice and easy to grasp authentication process inside my own application, with password recovery and everything else I need. And as soon as I or anyone else on the team wants to change the logic, she or he can just open their
app folders and go for it. So in my opinion, it is absolutely worth trying.
So, what is your experience with authentication in Rails apps? Ever tried to roll your own? Would you do so in your next project?