具有 domain/subdomain 架构的多租户 rails 应用程序,例如 Shopify
Multi-tenant rails application with a domain/subdomain architecture like Shopify
我正在构建一个类似于 Shopify 的多租户 rails 应用程序。每当客户注册 Account
时,他们都会在 customer.myapp.com
处创建一个子域。此子域 return 是一个视图,其中包含与其帐户相关的数据(包括 /admin 区域)。
现在在某些情况下,客户希望使用他们自己的自定义域,而不是为他们创建的子域。我需要如何将我的 rails 路由和控制器调整为 return 包含与客户帐户相关数据的视图,不仅基于子域,还基于自定义域或子域?
这就是我设置 config/routes.rb
来处理子域的方式:
# config/routes.rb
Rails.application.routes.draw do
...
constraints(SubdomainRequired) do
scope module: :accounts do
...
end
end
end
app/constraints/subdomain_required.rb
看起来像这样:
# app/constraints/subdomain_required.rb
class SubdomainRequired
def self.matches?(request)
request.subdomain.present? && request.subdomain != "www"
end
end
最后我的 app/controllers/accounts/base_controller.rb
根据请求子域设置当前帐户:
# app/controllers/accounts/base_controller.rb
module Accounts
class BaseController < ApplicationController
before_action :set_current_account
...
def set_current_account
if request.subdomain.present?
@current_account = Account.find_by(subdomain: request.subdomain)
render_404 if !@current_account
end
end
def render_404
render file: "#{Rails.root}/public/404.html", status: 404
end
...
end
end
对于 DNS 设置,我遵循了 Shopify 等公司的方法。看起来他们让他们的客户创建了一个指向他们应用程序的主要 IP 地址的 A 记录。他们让他们为“www”子域创建一个 CNAME,它指向一个子域 (sites.myapp.com
),设置为应用程序子域的 CNAME(在我的例子中由 DigitalOcean 的应用程序平台管理)。
如果 DNS 设置按预期工作,我想知道如何在客户登陆我的应用程序时将请求指向正确的方向。因此,例如,如果流量命中 customer.com
并且它有一个指向我的服务器主 IP 的 A 记录,加上 sites.myapp.com
的 CNAME,我如何处理请求并将其重定向到正确的子域,同时保持用户在他们的自定义域上?
这些是我目前检查过的资源:
- multi tenant with custom domain on rails
- Multi-tenant dynamic multiple domains with SSL pointing to single Host/CDN
- https://answers.netlify.com/t/subdomain-and-custom-domain-based-multi-tenant-application/30482/2
- https://www.indiehackers.com/post/how-do-i-setup-a-domain-to-subdomain-architecture-like-shopify-70413820da
- https://help.shopify.com/en/manual/online-store/domains/add-a-domain/using-existing-domains/connecting-domains#set-up-your-existing-domain-to-connect-to-shopify
感谢您的帮助!
好的,这就是我在此期间想到的。
首先,我如上所述离开了 config/routes.rb
。那里的一切似乎都在按预期工作。
然后我调整了 app/constraints/subdomain_required.rb
以不仅检查子域而且还检查请求的域部分:
# app/constraints/subdomain_required.rb
class SubdomainRequired
def self.matches?(request)
request.subdomain.present? && request.subdomain != "www" ||
request.domain.present? && request.domain != ENV["APP_DOMAIN"]
end
end
最后但同样重要的是,我将 app/controllers/accounts/base_controller.rb
中的 set_current_account
方法更改为这个 if 语句的怪物:
# app/controllers/accounts/base_controller.rb
module Accounts
class BaseController < ApplicationController
before_action :set_current_account
...
def set_current_account
@current_account = if request.domain.present? && request.domain != ENV["APP_DOMAIN"]
# Do custom domain stuff
if request.subdomain == "www" || !request.subdomain.present?
# Set current account by custom domain, e.g. custom.com
Account.find_by(domain: request.domain)
else
# Set current account by custom subdomain, e.g. site.custom.com
Account.find_by(domain: "#{request.subdomain + "." + request.domain}")
end
elsif request.subdomain.present? && request.subdomain != "www"
# Set current account by subdomain, e.g. site.myapp.com
Account.find_by(subdomain: request.subdomain)
end
render_404 unless @current_account
end
...
end
end
截至目前,我仍在测试我的解决方案。可能需要进行更多调整,当然还需要进行一些重构,但它似乎在起作用。
我必须解决的另一个(意外的)问题是整个 DNS 设置。与 heroku 类似,DigitalOcean 的应用程序平台不支持静态 IP 地址,因此客户端无法仅创建 A 记录,指向我的应用程序的 IP 地址,因为它可能随时更改。
现在我已经基于以下 heroku 示例使用 NGINX 设置了一个转发代理(你怎么称呼它?):
https://help.heroku.com/YTWRHLVH/how-do-i-make-my-nginx-proxy-connect-to-a-heroku-app-behind-heroku-ssl
希望对正在寻找类似解决方案的任何人有所帮助。
如果需要详细说明,请告诉我。
我正在构建一个类似于 Shopify 的多租户 rails 应用程序。每当客户注册 Account
时,他们都会在 customer.myapp.com
处创建一个子域。此子域 return 是一个视图,其中包含与其帐户相关的数据(包括 /admin 区域)。
现在在某些情况下,客户希望使用他们自己的自定义域,而不是为他们创建的子域。我需要如何将我的 rails 路由和控制器调整为 return 包含与客户帐户相关数据的视图,不仅基于子域,还基于自定义域或子域?
这就是我设置 config/routes.rb
来处理子域的方式:
# config/routes.rb
Rails.application.routes.draw do
...
constraints(SubdomainRequired) do
scope module: :accounts do
...
end
end
end
app/constraints/subdomain_required.rb
看起来像这样:
# app/constraints/subdomain_required.rb
class SubdomainRequired
def self.matches?(request)
request.subdomain.present? && request.subdomain != "www"
end
end
最后我的 app/controllers/accounts/base_controller.rb
根据请求子域设置当前帐户:
# app/controllers/accounts/base_controller.rb
module Accounts
class BaseController < ApplicationController
before_action :set_current_account
...
def set_current_account
if request.subdomain.present?
@current_account = Account.find_by(subdomain: request.subdomain)
render_404 if !@current_account
end
end
def render_404
render file: "#{Rails.root}/public/404.html", status: 404
end
...
end
end
对于 DNS 设置,我遵循了 Shopify 等公司的方法。看起来他们让他们的客户创建了一个指向他们应用程序的主要 IP 地址的 A 记录。他们让他们为“www”子域创建一个 CNAME,它指向一个子域 (sites.myapp.com
),设置为应用程序子域的 CNAME(在我的例子中由 DigitalOcean 的应用程序平台管理)。
如果 DNS 设置按预期工作,我想知道如何在客户登陆我的应用程序时将请求指向正确的方向。因此,例如,如果流量命中 customer.com
并且它有一个指向我的服务器主 IP 的 A 记录,加上 sites.myapp.com
的 CNAME,我如何处理请求并将其重定向到正确的子域,同时保持用户在他们的自定义域上?
这些是我目前检查过的资源:
- multi tenant with custom domain on rails
- Multi-tenant dynamic multiple domains with SSL pointing to single Host/CDN
- https://answers.netlify.com/t/subdomain-and-custom-domain-based-multi-tenant-application/30482/2
- https://www.indiehackers.com/post/how-do-i-setup-a-domain-to-subdomain-architecture-like-shopify-70413820da
- https://help.shopify.com/en/manual/online-store/domains/add-a-domain/using-existing-domains/connecting-domains#set-up-your-existing-domain-to-connect-to-shopify
感谢您的帮助!
好的,这就是我在此期间想到的。
首先,我如上所述离开了 config/routes.rb
。那里的一切似乎都在按预期工作。
然后我调整了 app/constraints/subdomain_required.rb
以不仅检查子域而且还检查请求的域部分:
# app/constraints/subdomain_required.rb
class SubdomainRequired
def self.matches?(request)
request.subdomain.present? && request.subdomain != "www" ||
request.domain.present? && request.domain != ENV["APP_DOMAIN"]
end
end
最后但同样重要的是,我将 app/controllers/accounts/base_controller.rb
中的 set_current_account
方法更改为这个 if 语句的怪物:
# app/controllers/accounts/base_controller.rb
module Accounts
class BaseController < ApplicationController
before_action :set_current_account
...
def set_current_account
@current_account = if request.domain.present? && request.domain != ENV["APP_DOMAIN"]
# Do custom domain stuff
if request.subdomain == "www" || !request.subdomain.present?
# Set current account by custom domain, e.g. custom.com
Account.find_by(domain: request.domain)
else
# Set current account by custom subdomain, e.g. site.custom.com
Account.find_by(domain: "#{request.subdomain + "." + request.domain}")
end
elsif request.subdomain.present? && request.subdomain != "www"
# Set current account by subdomain, e.g. site.myapp.com
Account.find_by(subdomain: request.subdomain)
end
render_404 unless @current_account
end
...
end
end
截至目前,我仍在测试我的解决方案。可能需要进行更多调整,当然还需要进行一些重构,但它似乎在起作用。
我必须解决的另一个(意外的)问题是整个 DNS 设置。与 heroku 类似,DigitalOcean 的应用程序平台不支持静态 IP 地址,因此客户端无法仅创建 A 记录,指向我的应用程序的 IP 地址,因为它可能随时更改。
现在我已经基于以下 heroku 示例使用 NGINX 设置了一个转发代理(你怎么称呼它?): https://help.heroku.com/YTWRHLVH/how-do-i-make-my-nginx-proxy-connect-to-a-heroku-app-behind-heroku-ssl
希望对正在寻找类似解决方案的任何人有所帮助。
如果需要详细说明,请告诉我。