How are people testing rails 3.1 + force_ssl?
Asked Answered
S

10

9

The force_ssl function in rails 3.1 is hardcoded to ignore the development environment, but not test. This is giving me redirect errors in my (minitest) tests. Is the solution to set up my test server to support ssl (if so, how?). If not, should I monkey patch force_ssl to ignore requests in test?

 def force_ssl(options = {})
        host = options.delete(:host)
        before_filter(options) do
          if !request.ssl? && !Rails.env.development?
            redirect_options = {:protocol => 'https://', :status => :moved_permanently}
            redirect_options.merge!(:host => host) if host
            flash.keep
            redirect_to redirect_options
          end
        end
  end

EDIT Found this chain, which confirms other people think this an issue, but doesn't look like there's a committed fix yet: https://github.com/rails/rails/pull/2630

Sidnee answered 24/1, 2012 at 15:25 Comment(0)
P
18

Another option instead of monkey patching the entire application is to just override force_ssl in your test suite alone. For example, in test/test_helper.rb you can add this:

# We don't want SSL redirects in our test suite
module ActionController::ForceSSL::ClassMethods
  def force_ssl(options = {})
    # noop
  end
end
Pirn answered 2/2, 2012 at 19:51 Comment(2)
this seems like a better approachSidnee
I have this at the end of my test_helper.rb file, and all is well running specs with spork. But just running rspec seems to ignore this. Any idea why?Cobbs
P
17

Here's another approach, if you don't want to mess with monkey-patching... you can use a before filter. This is rspec, not minitest syntax, but you get the idea:

before(:each) do
  request.env["rack.url_scheme"] = "https"
end

This convinces your controller that it got an SSL request.

A benefit of taking this approach is that you can actually write a test to ensure your controller requires SSL. :)

Patisserie answered 15/3, 2012 at 21:44 Comment(1)
Where did you put this? I get NameError: undefined local variable or method request'`Garretgarreth
H
4

That's what I ended up doing after recently upgrading to Rails 3.1 and switching to the force_ssl filter. Monkey patch to the rescue!

In a new file at config/initializers/ignore_force_ssl_in_test.rb

module ActionController
  module ForceSSL
    module ClassMethods
      def force_ssl(options = {})
        before_filter(options) do
          if !request.ssl? && !Rails.env.development? && !Rails.env.test?
            redirect_to :protocol => 'https://', :status => :moved_permanently
          end
        end
      end
    end
  end
end
Halitosis answered 26/1, 2012 at 16:26 Comment(2)
Great, this works for me. I'm going to accept your answer, but if/when this gets incorporated into rails I'll come back and add a noteSidnee
This will skip out any parameters in the URL, I'm pretty sure. Look at this link to get around that: #11253410Dormant
K
4

If you are interested in testing with varying SSL, I did this on the setup of the functional test.

def setup
  @request.env['HTTPS'] = 'on'
end
Kubis answered 7/1, 2013 at 21:13 Comment(0)
R
3

What worked for me is similar to Kelly Sutton's. I monkey patches force_ssl to ignore ssl requests in test environment, otherwise use the original rails implementation:

module ActionController
  module ForceSSL
    module ClassMethods
      alias_method :original_force_ssl, :force_ssl

      def force_ssl(options = {})
        unless Rails.env.test?
          original_force_ssl(options)
        end
      end
    end
  end
end
Rooted answered 6/3, 2013 at 19:56 Comment(3)
Ryan's approach seems similar to this except his code only runs in the test environment. I think putting his block in test.rb is better than running your block in all environments?Sidnee
Ryan's approach didn't work for me because force_ssl is a class method. spec_helper.rb will load the Rails environment first, then your code, thus effectively calling the original force_ssl and not the one defined in spec_helper.rbRooted
This is the only solution posted here that worked for me. Rails 3.2.13 and Rspec with Capybara and Selenium. Thanks!Heurlin
E
2

This approach of Simon Carletti's works nicely: http://www.simonecarletti.com/blog/2011/05/configuring-rails-3-https-ssl/

# config/application.rb
module MyApp
  class Application < Rails::Application
    config.force_ssl = true
  end
end

# config/environments/test.rb
MyApp::Application.configure do
  config.force_ssl = false
end
Echidna answered 29/1, 2013 at 16:55 Comment(0)
S
2

If you are looking for an answer in 2013. You can simply do:

force_ssl if: :ssl_configured?

  def ssl_configured?
    !Rails.env.test?
  end

Source: http://edgeapi.rubyonrails.org/classes/ActionController/ForceSSL/ClassMethods.html

Snuck answered 10/7, 2013 at 7:17 Comment(0)
P
1
force_ssl unless Rails.env.test?
Prescott answered 30/8, 2013 at 18:39 Comment(0)
G
0

You can make test calls to app using ssl!

  • use full uri with protocol https://eample.org/my/route/here in get 'https://eample.org/my/route/here'
  • or use https!(true) and https!(false) to dynamically change behavior in INTEGRATION TEST

    https!(true)
    get "/users"
    https!(false)
    

For CONTROLLER you do not have to use SSL, because (I think) they directly call action as method, without routing and other transfer stuff.

Grenier answered 30/3, 2016 at 10:2 Comment(0)
F
0

Rails docs recommend using if: ssl_configured? with the force_ssl call. You can then do:

   def ssl_configured?
    !Rails.env.development? && !Rails.env.test?
   end

Without having to monkey patch as official answer indicates.

Fontenot answered 19/10, 2016 at 17:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.