4

我知道我不应该这样做,但我不知道我该怎么做。我想根据登录的用户使用不同的数据库。所以我认为最好的方法是在第一次用户登录时设置会话变量......

这是它的样子:

class Stuff < ActiveRecord::Base
    establish_connection(
        :adapter  => "mysql2",
        :host     => "127.0.0.1",
        :username => session["dbuser"],
        :password => session["dbuserpass"],
        :database => session["dbname"])

这当然行不通。有谁知道如何做到这一点?谢谢你。

4

4 回答 4

3

您可以将方法重写为:

class Stuff < ActiveRecord::Base
 def establish_connection_user(user, pass, database)
   establish_connection(
    :adapter  => "mysql2",
    :host     => "127.0.0.1",
    :username => user,
    :password => pass,
    :database => database)
  end
end

在你的控制器中:

  class StuffController < ApplicationController
    def login #example 
      stuff = Stuff.new
      stuff.establish_connection_user(
        session[:dbuser], 
        session[:dbuserpass],
        session[:dbname]) 
    end

这样,您还可以封装它并使细节不那么明显。我建议你也加密你的 cookie,这样你就不会暴露凭据。你可以从这个答案中得到一个想法:

使用 Rails 存储加密的 cookie

于 2013-02-19T15:22:34.750 回答
1

您可以像这样在模型中选择数据库:

establish_connection "db_name_#{session[:something]}"

这样,您的模型就知道要拉/推数据的数据库。

看看这个: http: //m.onkey.org/how-to-access-session-cookies-params-request-in-model

于 2013-02-05T00:42:42.253 回答
0

如果您可以选择使用 PostgreSQL,则可以使用 PostgreSQL 的模式特性为每个用户有效地拥有单独的表命名空间(模式)。这样做的好处是您仍然连接到同一个数据库(从而避免破坏 Rails API),但在数据库分离方面您可以获得多个 DB 的相同好处。

如果您订阅了 RailsCasts Pro(9 美元/月),Ryan Bates 有一个关于这个主题的精彩视频:http ://railscasts.com/episodes/389-multitenancy-with-postgresql

Jerod Santo 在他的博客上也写了一篇很棒的文章:http: //blog.jerodsanto.net/2011/07/building-multi-tenant-rails-apps-with-postgresql-schemas/

在这两个示例中,他们都使用子域在租户/模式之间切换,但您可以轻松地将其链接到用户记录。

于 2013-02-23T20:11:55.420 回答
0

正如 kwon 在对原始问题的评论中所暗示的那样,我将通过使用会话来处理它,仅保留用户的身份。然后,我将从模型中的逻辑和一个中央数据库(默认的 rails DB)中提取所需的数据库连接,以保存用户详细信息和用户连接信息。

从修改您的用户模型开始(假设您的用户有一个保存在中央数据库中的模型)

  • 向用户添加一个属性,表示要使用的数据
  • 在您的应用程序控制器中,根据会话密钥在 before_filter 中设置用户
  • 使用用户参数初始化您的 Stuff 模型

然后,您可以根据 database.yml 查找您的数据库连接。或者,如果每个用户有一个数据库,并且您需要它是动态的,则创建第二个模型(在中央数据库中)表示与用户模型上的外键的数据库连接。

以下是一堆在现实中可能有效也可能无效的代码,但希望能为您提供一个入门模板。

class ApplicationController < ActionController::Base
  before_filter :set_user

  def set_user
    begin
      @user = UserProfile.find(session[:usernumber]) if session[:usernumber]        
    rescue
      logger.warn "Possible error in set_user. Resetting session: #{$!}"
      @user=nil
      session[:usernumber]=nil
      reset_session
    end
  end

end

class StuffController < ApplicationController
  def show
    @stuff = Stuff.user_get(@user, params[:id])
  end
end

class Stuff < ActiveRecord::Base
  # This would be better moved to a module to reuse across models
  def self.establish_connection_user(user)
    establish_connection(user.connection_hash)
  end
  def establish_connection_user(user)
    establish_connection(user.connection_hash)
  end

  def self.user_get user, item_id        
    establish_connection_user(user)
    find(id)
  end

  def self.user_where user, *query_args        
    establish_connection_user(user)
    where(query_args)
  end
  # Even better than replicating 'where', create model methods 
  # that are more representative of your desired functionality
end

class User  < ActiveRecord::Base
  has_one :user_connection
  def connection_hash
    uc = self.user_connection
    {:database=>uc.db, :password=>uc.pass, :user=>uc.username, :host=>uc.dbhost, :adapter=>uc.adapter}
  end
  # User probably contains other user-facing details
end
于 2013-02-19T19:30:00.010 回答