LoginSignup
10
6

More than 5 years have passed since last update.

Railsアプリで、force_sslでないアクションではHTTPSからHTTPへのリダイレクトを強制する

Posted at

前提

  • Rails 4.2.x
  • Ruby 2.3

本題

RailsアプリでSSLを強制させたい場合、つまり HTTP -> HTTPS のリダイレクトをさせたい場合は、
force_sslを使うことができます。

class HogeController < ApplicationController
  force_ssl only: :new
end

ここで、やんごとなき理由で HTTP -> HTTPS のリダイレクトが不要なアクションは必ずHTTPでアクセスさせたい、という要求があったとしましょう。
このときHTTPのページのみを行き来していれば何も問題はないのですが、一度HTTPSのページを経由すると、以降相対パスによる遷移はすべてHTTPSとなってしまいます。
つまり、明示的に HTTPS -> HTTP のリダイレクトを行わないといけません。

force_sslを使っているという前提で、どうすればよいかちょっと考えてみました。
普通に考えるとrequest.ssl? #=> trueのときにHTTPへリダイレクトする、という処理を書けば良いのですが、force_sslの対象となるアクションはその処理を実行したくないです(リダイレクトループになってしまうので)。

すぐに思いついたのはforce_sslが追加するCallbackの中身をCallbackChainから探して判定するという方法ですが、これはCallbackChainに入るときにはすでにlambdaに変換されていてあとからそのメソッド名とオプションを判定しづらい(できない?)のと、思わぬバグを仕込んでしまいそうで怖いので見送りました。

そこで、ひとつの実装として下記のようにしてみました。

class ApplicationController < ActionController::Base
  include SslRedirectable
end

class HogeController < ApplicationController
  force_ssl only: :new
end

module SslRedirectable
  extend ActiveSupport::Concern

  included do
    before_action :force_non_ssl, if: :force_non_ssl?

    class_attribute :ssl_actions

    SSL_ACTIONS_ALL = [:all]

    def self.force_ssl(options = {})
      self.ssl_actions = options[:only] || SSL_ACTIONS_ALL
      super
    end
  end

  def force_non_ssl?
    request.ssl? && request.get? && !ssl_required?
  end

  def ssl_required?
    return false unless ssl_actions
    ssl_actions.include?(action_name.to_sym) || ssl_actions == SSL_ACTIONS_ALL
  end

  def force_non_ssl
    redirect_to non_ssl_url
    flash.keep
  end

  def non_ssl_url
    URI(request.original_url).tap { |u| u.scheme = 'http' }.to_s
  end
end

force_sslを呼び出したときの対象のアクションをclass_attributeとして保持しておき、あとで当該アクションが呼ばれた時に参照する、というアプローチにしてみました。
force_sslをオーバーライドして拡張していますが、このくらいなら変更に弱くないだろうし、既存コードに手を加えずに実現できるメリットが大きいのでありかな、という感じです。
ここおかしくね?とか、もっとスマートな方法があるとか、ご意見あればぜひお願いします!

10
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
6