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

发布于 2024-09-25 22:53:44 字数 1915 浏览 5 评论 0原文

我正在尝试设置 has_many :through 两个模型之间的关系 User 和 CustomerAccount 通过另一个联接模型 AccountOwnership (users 和 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

config/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”和“users”表包含在 一个默认数据库(例如 db1),“customers”表包含在 不同的数据库(例如 db2)。与数据库的连接是 配置正确,但在查找过程中,因为只有一个数据库 连接对象可用,Rails 尝试查找 account_ownerships db2 中的数据库因此失败。

看来我的设计/逻辑可能有缺陷,因为我看不到办法 使用相同的数据库连接连接到两个不同的数据库,但我 会很高兴看到是否有解决方法,而不改变 设计。 (我不愿意改变设计,因为db2不在我的之下 control)

看来我可以通过将 account_ownerships 表移至 db2 来解决此问题,但这至少对我来说不太理想。

是否有任何替代机制/模式来设置此关联 导轨。

提前致谢。 中号

I am trying to setup a has_many :through relationship between two models
User and CustomerAccount through another join model AccountOwnership
(users and account_ownerships tables are in one db, say db1 and the customer_accounts table is in remote db, say db2).

Here is the relevant code, that sets up the associations

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

config/database.yml (configuration is correct, although not shown here)

development:
  reconnect: false
  database: db1
  pool: 5

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

In script/console

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

a.user ## Returns the correct user

a.company ## returns the correct CustomerAccount instance

also

a.user.account_ownership ## returns a as anticipated

but

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))

The issue here is that the "account_ownerships" and "users" tables are contained in
one default database (say db1), and the "customers" table is contained in
a different database (say db2). The connections to the databases are
configured properly, but during the lookup since there is only one database
connection object available, Rails tries to find the account_ownerships
database in db2 and hence fails.

It looks like my design/logic might be flawed because I cannot see a way
to connect to two different databases using the same db connection, but I
would be thrilled to see if there is a workaround, without changing the
design. (I am reluctant to change the design because db2 is not under my
control)

It looks like I can workaround this issue by moving my account_ownerships table to db2, but this less than ideal for me atleast.

Are there any alternate mechanisms/schemas to setup this association in
Rails.

Thanks in advance.
M

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

吾性傲以野 2024-10-02 22:53:45

解决方案:

似乎这无法通过任何 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 表中,因此这可能会在 users 方法中引起丑陋的 ActiveRecord::RecordNotFound 错误。

Solution:

Seems that this cannot be achieved through any Rails association magic, since this is a core limitation of any database access mechanism including raw SQL.

Here is what I did to workaround the issue:

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

This provides a correct approximation as shown:

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

ALSO

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

And we need to add two instance methods to the account_ownership model, to approximate
the association behavior

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

Now we can do

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

AND

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

CAUTION:
1. Since there is no delete cascading done on the CustomerAccount model, if any accounts are deleted, this will not be reflected in the account_ownership table, hence this can give rise to ugly ActiveRecord::RecordNotFound errors in the users method.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文