activerecord - Rails: 在不同数据库之间设置表之间的has_many_through关联

  显示原文与译文双语对照的内容
0 0

我正在尝试设置 has_many: 通过两个模型用户和CustomerAccount之间的关系,通过另一个连接模型 AccountOwnership ( 用户和account_ownerships表位于一个数据库中,比如db1和customer_accounts表位于远程数据库中,比如 db2 ) 。

下面是相关代码,它建立了关联


class User <ActiveRecord::Base
 has_many :account_ownerships, :dependent => :destroy
 has_many :companies, :through => :account_ownerships
end



class AccountOwnership <ActiveRecord::Base
 belongs_to :user
 belongs_to :company, :class_name =>"Reporting::CustomerAccount"
end


class CustomerAccount <Reporting::Base
 set_table_name 'customers'
 establish_connection("db2_#{RAILS_ENV}")
end

配置/database.yml ( 配置正确,但这里未显示)


development:
 reconnect: false
 database: db1
 pool: 5

db2_development:
 reconnect: false
 database: db2
 host: different.host
 pool: 5

在脚本/控制台中


a = AccountOwnership.new(:user_id => 2, :company_id => 10)

a.user ## Returns the correct user

a.company ## returns the correct CustomerAccount instance


a.user.account_ownership ## returns a as anticipated

但是


a.user.companies ## produces the following error:

#ActiveRecord::StatementInvalid: Mysql::Error: Table
#'db2.account_ownerships' doesn't exist: SELECT `customers`.* FROM
#`customers` INNER JOIN `account_ownerships` ON `customers`.id =
#`account_ownerships`.company_id WHERE ((`account_ownerships`.user_id
= 4))

这里的问题是"account_ownerships"和"用户"表包含在一个默认数据库( 说 db1 ) 中,而"客户"表包含在不同的数据库( 说 db2 ) 中。 到数据库的连接被正确配置,但是在查找过程中,因为只有一个数据库连接对象可用,Rails 试图在db2中找到account_ownerships数据库,因此失败了。

看起来我的设计/逻辑可能是有缺陷的,因为我无法使用相同的db连接来连接两个不同的数据库,但是我很高兴看到是否有一个解决方案,而不需要更改设计。 ( 我不愿意更改设计,因为db2不在我的控制之下)

看起来我可以通过将account_ownerships表移动到db2来解决这个问题,但至少这比我理想的理想。

是否有其他的机制/模式在 Rails 中设置这个关联。

请提前致谢。

时间: 原作者:

0 0

解决方法:

似乎这不能通过任何 Rails 关联魔术来实现,因为这是任何数据库访问机制( 包括原始 SQL )的核心限制。

以下是解决该问题的方法:


class User <ActiveRecord::Base
 has_many :account_ownerships, :dependent => :destroy

 def companies
 (account_ownerships.collect { |r| Reporting::CustomerAccount.find(r.company_id) }).flatten 
 end 
end

这提供了一个正确的近似值,如下所示:


a = AcccountOwnership.create!(:user_id => 10, :company_id => 10)
u = User.find(10)
u.account_ownerships ### will return the correct account_ownership instance


u.companies ### will return a list of all companies enlisted for each account

我们需要向account_ownership模型添加两个实例方法,以近似关联行为


class CustomerAccount <ActiveRecord::Base
 set_table_name"customers" 

 ########################################################
 ## This cannot be used because, customers and
 ## account_ownerships tables are contained in
 ## different databases, because of this it is 
 ## impossible to query these two tables from a
 ## single db connection, which is what we are
 ## attempting to achieve here.
 ## has_many :account_ownerships, :dependent => :destroy
 ########################################################

 def account_ownerships
 AccountOwnership.find(:all, :conditions => ["company_id =?", self.id])
 end

 def users
 (account_ownerships.collect { |r| User.find(r.user_id) }).flatten
 end
end

现在我们可以


c = CustomerAccount.find(10)
c.account_ownerships ## will return the right ownership accounts


c.users ## will iterate over all the accounts accumulating any users

警告:1.因为在CustomerAccount模型上没有删除级联,如果删除了任何帐户,这将不会反映在account_ownership表中,因此这会导致用户方法中出现丑陋的ActiveRecord::RecordNotFound 错误。

原作者:
...