116
106

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2014-09-04

目的は、サービス内のアカウントごとにサブドメインを利用できるようにすること。
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)の際にリダイレクトされたのが問題だったということ?

116
106
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
116
106

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?