1

我开发了一个应用程序,它使用具有多模式的 PostgreSQL 来实现应用程序的多租户端。租户是通过子域检查的,但我正在尝试找到一种方法来仍然能够将主域用作我自己的注册点和管理后端。

下面是我的应用程序控制器,我相信检查租户正在发生。

我从这里跟随 railscast http://railscasts.com/episodes/389-multitenancy-with-postgresql?view=comments

class ApplicationController < ActionController::Base


protect_from_forgery

  rescue_from CanCan::AccessDenied do |exception|
    redirect_to root_path, :alert => exception.message
  end

  before_filter :mailer_set_url_options

  def mailer_set_url_options
    ActionMailer::Base.default_url_options[:host] = request.host_with_port
  end

  around_filter :scope_current_tenant

private

  def current_user
    @current_user ||= User.find(session[:user_id]) if session[:user_id]
  end
 helper_method :current_user

  def current_tenant
    @current_tenant ||= Tenant.find_by_subdomain!(request.subdomain)
  end
  helper_method :current_tenant

  def scope_current_tenant(&block)
    current_tenant.scope_schema("public", &block)
  end
end

我注意到的另一个问题是通过设计。似乎是因为多租户,并且在应用程序控制器中定义助手 current_user 对设计中的会话很挑剔,有什么想法吗?

4

2 回答 2

1

If you do not have a tenant for your main domain (for eg. visitors) and current_tenant therefore is set to nil in that case, you cannot call current_tenant.scope_schema, but I believe you can do something like this:

 def current_tenant
   # Select tenant based on a user and set it to nil if no user:
   @current_tenant ||= current_user.tenant unless current_user.nil?
 end
 helper_method :current_tenant

 def scope_current_tenant(&block)
   if current_tenant.nil?
      scope_visitor_schema
      yield
   else
     current_tenant.scope_schema("public", &block)
   end
 end  

 def scope_visitor_schema()
   original_search_path = ActiveRecord::Base.connection.schema_search_path
   ActiveRecord::Base.connection.schema_search_path  = 'public'
 ensure
   ActiveRecord::Base.connection.schema_search_path = original_search_path
 end

In this example tenant is selected based on the user rather than a subdomain, but the approach is the same.

于 2015-02-26T20:41:09.403 回答
0

我找到了一个解决方案并忘记发布它,但你的评论让我记住了。这就是我在确定当前客户端范围时正在做的事情:

基本上我使current_id某些东西无效,在这种情况下"admin",当子域等于时"admin",并且不设置current_id子域为时www,或空白(我将用于主页。

希望这可以帮助

 def scope_current_client
  case  request.subdomain
    when /^admin$/
        Client.current_id = "admin"
    when /^www$|^$/

    else
        Client.current_id = current_client.id
  end
  yield
  ensure
    Client.current_id = nil         
end
于 2013-07-30T16:23:08.117 回答