Reputation: 3638
I'm running a Rails 3.1.4 app that needs to have some pages use force_ssl, but others that I don't want to have SSL. Is there an opposite to force_ssl, like force_http? The issue is that I have some pages that don't need to be SSL, and they contain elements that I can't pull over using https (so the user gets the insecure error from the browser).
What happens is that when someone goes to a force_ssl page it works fine, but then when they go to other pages where it is not force_ssl, they receive the insecure page error from the browser because the https remains. Therefore, I'd like to force the pages where I can't make the elements https avoid using use SSL (ie force it back to http).
Thank you in advance.
Upvotes: 2
Views: 2201
Reputation: 4612
Assuming (hoping) you've upgraded to a supported version of Rails, this is an easy way to achieve default non-SSL unless force_ssl
is declared. It's in the form of an ActiveSupport::Concern
:
module ForceNoSSL
extend ActiveSupport::Concern
ACTION_OPTIONS = [:only, :except, :if, :unless]
def force_no_ssl_redirect
if request.ssl?
options = {
:protocol => 'http://',
:host => request.host,
:path => request.fullpath,
:status => :moved_permanently
}
redirect_to ActionDispatch::Http::URL.url_for(options)
end
end
class_methods do
def force_ssl(options = {})
super
action_options = options.slice(*ACTION_OPTIONS)
skip_before_action :force_no_ssl_redirect, **action_options
end
def force_no_ssl
before_action :force_no_ssl_redirect
end
end
end
In your ApplicationController
you then:
include ForceNoSSL
force_no_ssl
How it works is that by default all actions will run the force_no_ssl_redirect
callback. If it's already a non-ssl connection then nothing will be done, otherwise the request will be redirected to http://
.
However, if you've declared force_ssl
then the force_no_ssl_redirect
callback will be skipped (only for those actions specified by the ACTION_OPTIONS
).
You could extend this to allow force_no_ssl
to accept URL options etc... like the force_ssl
action does, but for my use case this wasn't necessary.
P.S. A lot of this code comes from ActionController::ForceSSL
so check that out for more insight.
Upvotes: 0
Reputation: 517
Got this to work without a loop. Unless it happens in browsers I am not aware of.
before_filter do
unless params[:controller] == 'whatever_controller_name_you_are_serving_https_to'
if request.ssl? && Rails.env.production?
redirect_to :protocol => 'http://', :status => :moved_permanently
end
end
end
Upvotes: 0
Reputation: 5400
Ok, I found a way that seems to work for me:
In my sessions controller I added this:
force_ssl :only => [:new, :create]
So only those 2 actions will get called over SSL. Now, after a user successfully logs in, the page will redirect to a non-SSL connection.
As far as forcing the pages to be non-SSL, try this question: Rails 3.1 Force Regular HTTP, look for Joost's answer with a before_filter.
This is what he posted:
class ApplicationController < ActionController::Base
before_filter do
if request.ssl && Rails.env.production?
redirect_to :protocol => 'http://', :status => :moved_permanently
end
end
end
Disclaimer: The code above is not mine, I copied it from the question in the link, just putting it here for convenience. Please visit the above link to see it in its original context.
Also, regarding forcing non-SSL, I'm not sure that's a great idea. If a user requests an SSL connection and you have the certificates, why not give it to them? I agree that SSL does put more strain on the browser, but some people like surfing on SSL all the time. If you have some code that does not work over SSL than that is a valid reason to force non-SSL.
Cheers.
Upvotes: 5