28

I am upgrading an application to Rails 3.0.0 and am wondering if the standard method for adding SSL has changed (I vaguely remember demos indicating the router could now handle SSL, though I'm not sure if it was just for demonstration purposes). I currently use the "ssl_requirement" gem, however it gives:

DEPRECATION WARNING: Using #request_uri is deprecated. Use fullpath instead. (called from ensure_proper_protocol at /Library/Ruby/Gems/1.8/gems/ssl_requirement-0.1.0/lib/ssl_requirement.rb:53)

Also, it appears to break when handling the new 'data-method' attributes. For example:

<%= link_to "Logout", user_path, :method => :delete %>

Works fine when accessing from an SSL section of the application, but fails (attempts to render show action) when followed from a non-SSL section (all actions in the user controller require SSL, although I understand that the destroy action does not transmit secure data).

Kevin Sylvestre
  • 37,288
  • 33
  • 152
  • 232

4 Answers4

46

It's indeed pretty simple in Rails 3. In config/routes.rb:

MyApplication::Application.routes.draw do
  resources :sessions, :constraints => { :protocol => "https" }
end

Or if you need to force SSL for multiple routes:

MyApplication::Application.routes.draw do
  scope :constraints => { :protocol => "https" } do 
    # All your SSL routes.
  end
end

And linking to SSL routes can be done like this:

<%= link_to "Logout", sessions_url(:protocol => 'https'), :method => :delete %>

If you wish to automatically redirect some controllers (or actually, some subpaths) to an equivalent https-based URL, you can add something like this to your routes (I wish this part were simpler):

# Redirect /foos and anything starting with /foos/ to https.
match "foos(/*path)", :to => redirect { |_, request|
  "https://" + request.host_with_port + request.fullpath }
Community
  • 1
  • 1
molf
  • 73,644
  • 13
  • 135
  • 118
  • 1
    This seems to be more complex than using 'ssl_requirement'. Is it the new standard method of doing it in Rails 3 or is 'ssl_requirement' still usable? Thanks. – Kevin Sylvestre Sep 03 '10 at 15:58
  • 1
    @Kevin: Apart from the automatic redirection, I think it's pretty easy. Moreover, this is all possible with the *standard* routing DSL, something that couldn't be done in Rails 2, hence the need for an external library. – molf Sep 03 '10 at 16:11
  • 4
    In the development environment, do scope :constraints => { :protocol => Rails.env.production? ? 'https' : 'http' } do ... end Source: http://www.themomorohoax.com/2010/10/08/using-ssl-in-rails-3 – Ryenski Apr 27 '11 at 03:22
  • 5
    Note that in **Rails 3.1**, it is getting simpler: http://www.simonecarletti.com/blog/2011/05/configuring-rails-3-https-ssl/ – molf May 05 '11 at 21:27
  • The `match` rule you give creates a redirect loop. – Raphael Dec 21 '12 at 19:49
  • @KevinSylvestre How is this more complex? You could just use `scope` to wrap all your https routes in one place, as opposed to doing this in each individual controller and trying to keep track of that. It's way more DRY. – bigpotato Aug 29 '13 at 15:59
20

After spending an afternoon looking for the best solution I settled on the approach described in this article: http://clearcove.ca/blog/2010/11/how-to-secure-a-rails-app-on-heroku-with-ssl-firesheep/ which referenced this article: Force SSL using ssl_requirement in Rails 2 app

Basically do this:

# lib/middleware/force_ssl.rb
class ForceSSL
  def initialize(app)
    @app = app
  end

  def call(env)
    if env['HTTPS'] == 'on' || env['HTTP_X_FORWARDED_PROTO'] == 'https'
      @app.call(env)
    else
      req = Rack::Request.new(env)
      [301, { "Location" => req.url.gsub(/^http:/, "https:") }, []]
    end
  end
end

# config/application.rb
config.autoload_paths += %W( #{ config.root }/lib/middleware )

# config/environments/production.rb
config.middleware.use "ForceSSL"
Community
  • 1
  • 1
Dan
  • 1,729
  • 18
  • 11
14

Toppic is old but just for googling people:

in *app/controller/your_controller.rb*

 class LostPasswordsController < ApplicationController

   force_ssl

   def index
     #....
   end
 end 

if globally use it in application controller

http://apidock.com/rails/ActionController/ForceSSL/ClassMethods/force_ssl

...thx S.L. for tip

equivalent8
  • 13,754
  • 8
  • 81
  • 109
  • Thanks for this. Combined with the `except` and `only` options, this is a great solution for selective SSL. – LouieGeetoo Apr 04 '12 at 20:55
  • b.t.w. there is a differennce between `config.force_ssl` and controller `force_ssl` http://www.eq8.eu/blogs/14-config-force_ssl-is-different-than-controller-force_ssl – equivalent8 May 08 '16 at 10:08
1

In later Rails (at least 3.12+) you can use the following, environment-specific:

in config/environments/production.rb (or other environment)

# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
config.force_ssl = true
rcd
  • 1,348
  • 1
  • 14
  • 27