You don't need a gem - you can just write a little helper to do this.
in ApplicationController:
def force_ssl(options = {})
host = options.delete(:host)
unless request.ssl? or Rails.env.development?
redirect_options = {:protocol => 'https://', :status => :moved_permanently}
redirect_options.merge!(:host => host) if host
flash.keep
redirect_to redirect_options and return
else
true
end
end
And then in your controllers:
before_filter :force_ssl, :only => [:login]
This does not satisfy your second requirement of automatically choosing the https protocol on path helpers, but that's not achievable with a controller-specified SSL enforcement, since the route helpers don't care about what's happening on a controller level. That is actually mutually exclusive with controller-enforced SSL, because if your routes specify HTTPS, then they won't resolve a non-HTTPS URL to a controller action, which means that your force_ssl
filter would never be hit. You could achieve this by duplicating your routing, however, so that you have both HTTPS-scoped and unscoped routes, with the unscoped routes being defined before the HTTPS-scoped routes, so that the HTTPS-scoped versions assume the helper names. This does mean duplication, though.
You might be able to achieve that with a little helper method, though. I haven't tested this, but the concept should work:
def route_with_https_preference(&block)
&block.call
scope :protocol => 'https://', :constraints => { :protocol => 'https://' } do
instance_eval &block
end
end
route_with_https_preference do
resources :gizmos do
resources :widgets
end
end
You can achieve SSL-scoped routing in your routes file easily enough (see this answer for details), but it does mean that you have to use the _url
helpers rather than the _path
helpers, as a protocol switch requires a full-qualified URL.