Securing Devise routes with Rails 3 without ssl_requirement

We wanted to run all SSL, but we couldn't because we can't afford $10,000 or more for Google Maps Premier, which in turn would leave us with all manners of mixed content warnings. So we want to secure at least the account registration, edit, and log in sections, which is a compromise. Yes, we know you could get Firesheep'd or whatever, but we don't really work with super private data, so this is probably an ok compromise.

Problem: Secure Devise routes with SSL with Rails 3.

We considered using ssl_requirement, as there's a fork of it that supposedly works with Rails 3, but I didn't want to depend on some random fork. If someone releases and maintains a proper gem, we could use it though. Besides, the functionality you need is all in Rails 3 (it wasn't there in Rails 2), so why add another dependency?

Our solution:

We assume you took care of your certificates already. We also didn't want to deal with certs for development machines, because it's kind of annoying, but you could do that too. Production and staging are pretty much the same, so we'll leave out staging for the purposes of this discussion. We also assume you dealt with all your other mixed content warnings.

First, we needed to force certain routes to be secure. In routes.rb, define something that responds to "matches?" and use it as a constraint. Here's the code:

Second, after logging in, editing user, registration, etc. we need to redirect back to non-SSL, to avoid mixed content warnings from Google Maps JavaScript files. I had trouble doing this with routes. I think the only solution would be the "match" solution used for redirecting to SSL. Since the majority of the site is non-SSL, we'd have to write many, many lines, one for each route we have.

So instead, we'll do the redirect through Devise. I find this part of Devise's design kind of bad; I'd prefer a more declarative solution, so I might investigate redirecting with routes again later. For now, though, this was the easiest solution. To redirect, you have to override methods in two controllers, according to the Devise wiki.

That's it! It's not too complicated once you know what to do, but it takes a long time to figure out the first time.

Posted by Alvin Liang