使用会话变量设置数据库连接

时间:2013-02-05 00:32:12

标签: ruby-on-rails ruby rails-activerecord

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

这就是它的样子:

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

这当然不起作用。有谁知道如何做到这一点? 谢谢。

4 个答案:

答案 0 :(得分: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,以便您没有如此暴露的凭据。你可以采取一个想法 从这个回答:

Storing an encrypted cookie with Rails

答案 1 :(得分:1)

您可以在模型中选择数据库,如下所示:

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

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

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

答案 2 :(得分: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

答案 3 :(得分:0)

如果您可以选择使用PostgreSQL,则可以使用PostgreSQL的Schemas功能为每个用户有效地拥有单独的表名称空间(模式)。这里的好处是你仍然连接到同一个数据库(从而避免乱砍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/

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