Railsで環境毎にサブドメインとパスを切り替える
はじめに
先日、とあるAPIを作成していたときに
- 開発環境では、
http://localhost:3000/api/users/1
のように、パスの最初にapi
をつける。 - 本番環境では、
http://api.example.com/users/1
のように、apiというサブドメインを利用するためパス内のapi
は不要。
というルーティングをやらなくてはいけなくなったので、色々調べてみました。
実装例
先に完成形を示します。これを見ればだいたいわかるかと。
# config/routes.rb constraints Subdomain::Api do namespace :api, path: Subdomain::Api.path do resources :users end end
# lib/subdomain/api.rb module Subdomain class Api def self.matches?(request) if Rails.env.production? request.subdomain == "api" else request.subdomain.blank? end end def self.path "api" unless Rails.env.production? end end end
解説
環境毎にサブドメインを切り替える
環境とか関係なく特定のサブドメインにアクセスされた場合のルーティングを行いたいのであれば、以下のように書けばOKです。
# config/routes.rb constraints subdomain: "api" do resources :users end # => サブドメインが"api"のときにGET /users/:id等が有効になる
もう少し複雑なことをやりたい場合、constraints
メソッドの引数にインスタンスを渡し、そのインスタンスメソッドにmatches?
を用意します。このメソッドの中に、引数のrequest
(コントローラーで使えるものと同じ)を使った処理を書きます。メソッドの戻り値がtrue
なら、ブロック内のルーティングが有効になるという仕組みです。
上記の実装例では、Subdomain::Api
のクラスメソッドとしてmatches?
を実装し、この中で環境毎に分岐した処理を行っています。そして、このクラスをconstraints
メソッドに渡すことで、環境毎に切り替えを行っています。
環境毎にパスを切り替える
パスの切り替えでは、namespace
メソッドのpath
オプションを使います。
このオプションを使うことで、コントローラーとは別の名前空間が利用できます。
また、nil
を指定するとパスがつかなくなる(=scope
メソッドでmodule
オプションを使ったときと同様の挙動になる)のがポイントです。
つまり、以下の2つは等価なコードです。
namespace "api", path: nil do resources :users end scope module: "api" do resources :users end
上記の実装例では、Subdomain::Api
のクラスメソッドとしてpath
を実装し、production以外では"api"
という文字列を返すようにしています。そして、この値をpath
オプションに渡すことで、環境毎に切り替えを行っています。
おわりに
書きながら、これと同じことやりたい人いるのかなって思ったけど備忘録も兼ねて頑張って書いた。