106
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

updated at

Railsでリソースごとにサブドメインを分ける運用

目的は、サービス内のアカウントごとにサブドメインを利用できるようにすること。
Shopというリソースはdomain_nameを持ち、http://example.com/:domain_nameshops#showにルーティングされるようにしている。これをhttp://domain_name.example.com/shops#showにアクセスできるようにする。

参考

はじめに

  • 開発環境でサブドメインの検証をするにはlvh.meを使う
    • http://lvh.me:3000でローカルホストにアクセスできる

ルーティング設定

lib/subdomain.rbの作成

このクラスをルーティングに用いる。

class Subdomain
  def self.matches?(request)
    # wwwの場合は追加するルーティングにマッチングしないようにしておく
    request.subdomain.present? && request.subdomain != 'www'
  end
end

config/routes.rbの設定

shopsリソースについて、Shopモデルはdomain_nameという項目を持ち、showアクションの際に、
domain_nameをキーにして取得している。

  # config/routes.rb
  require Rails.root.join('lib', 'subdomain.rb')

  constraints Subdomain do # サブドメインが指定されていた場合に以下のルーティングが利用される
    get 'shop', to: 'shops#show', path: '/' # サブドメインごとのルートパスという感じ?
  end

  # ちなみにサブドメイン導入前にのルーティング(残している)
  get 'domain_shop', to: 'shops#show', path: ':domain_name', constraints: { format: /()/ }

コントローラ側

constraints Subdomain do内でルーティングされた際には、request.subdomainが取得できる。
なので、shops#showでshopインスタンスを取得する処理を以下のように変更する。

def set_shop_by_domain_name
  if request.subdomain.blank?
    @shop = Shop.find_by!(domain_name: params[:domain_name])
  else
    @shop = Shop.find_by!(domain_name: request.subdomain)
  end
rescue
  redirect_to root_url(subdomain: false), notice: 'error message'
  # サブドメインが指定されたがShopにレコードがない場合にリダイレクトループになるので、
  # sudbomain: falseでサブドメインを除外しておく。
end

Cookieをサブドメインで共有する

注意点は、参考リンクなどにもあるようにセッションの削除ができなくなるケースに陥らないこと。
セッションストアの設定は、環境ごとに分ける記事がいくつかあったけれど、以下の設定でいけた。

# config/initializers/session_store.rb
Rails.application.config.session_store :cookie_store, key: key_name, domain: :all

サブドメインとメインドメイン間のルーティング

このままでは、サブドメインでルーティングされた後にroot_urlがsudbomain.example.jpという風に固定されてしまう。

link_toなりでリンクを作成する際に、以下のようにするとサブドメインをクリアできるみたい。

link_to 'link_name', root_url(subdomain: false)

CORS?

以下の様なエラーが発生。

ActionController::InvalidCrossOriginRequest - Security warning: an embedded <script> tag on another site requested protected JavaScript. If you know what youre doing, go ahead and disable forgery protection on this action to permit cross-origin JavaScript embedding.:

サブドメインから、メインドメインへ移るためにルーティングで以下のように設定していた。

  constraints Subdomain do
    get 'shop', to: 'shops#show', path: '/'
    get '*a' => redirect(subdomain: false) #, constraints: { format: :html }
    # この部分でサブドメインからメインドメインにリダイレクトしていて、そのJSがエラーになっていた。
  end

メインドメインへ移るリンクはroot_url(subdomain: false)を使うように決めた。

関係ないけれど

最初は、CORSについて調べていたがAPIに対する記述ばかりみていた。意味がわからなかった。gemのrack-corsを使ったりしていたが、gemに問題があるような記事があったりして、良くわからなかった。せっかく調べたので設定箇所などをメモしておく。

    # conifg/application.rb
    config.middleware.use Rack::Cors do
    # 以下のようにする必要があるケースがあるらしい
    #config.middleware.insert_before ActionDispatch::Static, Rack::Cors do
      allow do
        #origins '*'
        origins 'http://*.lvh.me:3000', '127.0.0.1:3000', 'localhost:3000', /http:\/\/.*\.lvh\.me:(\d*)/
        resource '*', headers: :any, :methods => [:get, :post, :delete, :put, :options]
      end
    end

けれど、responseのheaderに以下の様なヘッダーは入ってこなかった。コントローラをいじらなければならないのか?クライアントサイドの開発・APIの開発の際にもう一度調べることになりそう。

Access-Control-Allow-Methods →GET, POST, PUT, DELETE
Access-Control-Allow-Origin →*

ちなみに問題となっていたJSの処理は以下。

$('#id').val(this.value);
$.ajax({
  type: 'GET',
  url: '/controller_a/action'
});

Rendered controller_a/action.js.erb (89.7ms)の際にリダイレクトされたのが問題だったということ?

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sign upLogin
106
Help us understand the problem. What are the problem?