読者です 読者をやめる 読者になる 読者になる

woshidan's blog

そんなことよりコードにダイブ。

urlヘルパを使ってプロトコルがhttpsのurlを吐き出させたい

Rails4 Rails urlヘルパー Ruby on Rails

なんか調べてたら、Railsのurlヘルパーでhttpsの指定ができる、という話を見かけて、よく分からなかったので調べてみました。

前もって把握していた情報は

  • *_urlヘルパは、完全URIを返す
  • *_pathヘルパは、パス以下を返す

だったので、これじゃなんともいえないなと手に入った情報をいくつか検証してみました。

検索して出てきた関連しそうな情報と参考元

*_pathヘルパー + config/routes.rb

httpsはできませんでした。

検証コード

# config/routes.rb
resources :products, constrains: { protocol: 'https'}

# view
<%= link_to 'products_path', products_path %>
<%= link_to 'products_path_only_path_false', products_path, :only_path => false %>
#=> http://localhost:3000/products

*_urlヘルパにprotocol: 'https'オプションを与える

httpsはできました。しかし、参考先を見てたらこれどっちかというと、Modelとかにurlヘルパをインクルードして使いたいけれど、デフォルトのコントローラでのhostやschemaの設定が効かない場合に使うみたいです。

検証コード

<%= link_to 'products_url_with_option', products_url(protocol: 'https') %>
#=> https://localhost:3000/products

environments/xxx.rbで config.action_controller.default_url_optionsをいじる

これは*_pathはいけませんでしたが、*_urlヘルパはいけました。

検証コード

class ProductsController < ApplicationController
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception

  def default_url_options
    # テスト用に開発環境だけhttps
    Rails.env.development? ? { protocol: :https }.merge(super) : super
  end

  def index
  end
end
<%= link_to 'products_path', products_path %>
#=> http://localhost:3000/products
<%= link_to 'products_url', products_url %>
#=> https://localhost:3000/products

*_urlヘルパはコントローラのリダイレクトでプロトコルを変わるので完全URIが必要、とかいう場合に使うもので、以外調べている感じ、force_sslあたりのメソッドを使う方が健全な気がします。

あと、*_urlヘルパがコントローラのリダイレクト等でプロトコルを変わったり、外部ページへのアクセスになるので完全URIが必要といった場合に使うもので、*_pathヘルパはviewのサイト内リンクでは一文字でも文字を減らしておきたいよね、みたいな場合に使うものだとスタックオーバーフローで紹介されていたのが、面白かったです。

*path are for views because ahrefs are implicitly linked to the current URL. So it’d be a waste of bytes to repeat it over and over. In the controller, though, *url is needed for redirect_to because the HTTP specification mandates that the Location: header in 3xx redirects is a complete URL.

http://stackoverflow.com/questions/2350539/what-is-the-difference-between-url-and-path-while-using-the-routes-in-rails

その他メモ

全般的に、読んでいた傾向として、この手の事をしたいとき、コントローラのデフォルト設定をいじるより、コントローラの方でforce_sslを使って全体のプロトコルを設定して、ビューでは*_pathヘルパーを使うのがよさそうな気がしました。

普通は一部だけhttp/httpsにするから、その部分の判定メソッドの条件分岐がややこしくなってきたら、その段で分岐条件は設定ファイルに置いといた方がよさそう、という感じです。

あと、関係ないですが、スキーマとかプロトコルとかの言い方がごっちゃになっていて謎だったのでもう少し調べたら、スキーマURIの命名法が何かを示す部分で、そこにプロトコル名(http, https)を入れて、このURIはhttpのプロトコルに合わせて書いていますよ、と言う風に示すものらしいことが分かりすっきりしました。