0

我有三个模型,警报,站点,网络。它们通过 belongs_to 关系连接,但它们存在于不同的数据库中

class Alarm < ActiveRecord::Base
   establish_connection :remote
   belongs_to :site, primary_key: :mac_address, foreign_key: :mac_address
end

class Site < ActiveRecord::Base
   establish_connection :remote
   belongs_to :network
end

class Network < ActiveRecord::Base
   establish_connection :local
end

我希望选择属于特定网络的所有警报。我可以在如下范围内使用原始 sql 执行此操作:

scope :network_alarms, lambda { |net|
    #need to ensure we are interrogating the right databases - network and site are local, alarm is remote
    remote=Alarm.connection.current_database
    local=Network.connection.current_database
    Alarm.find_by_sql("SELECT network.* FROM #{local}.network  INNER JOIN #{local}.site ON network.id = site.network_id  INNER JOIN #{remote}.alarm on #{remote}.alarm.mac_address = site.mac_address WHERE site.network_id=#{net.id}")
  }

这很好用。但是,这个范围返回一个数组,所以我不能链接它(例如,使用with_paginate's #page方法)。所以

有没有更智能的方式来做这个加入。例如,我尝试过使用joinandwhere语句(这是我尝试过的众多变体之一):

scope :network_alarms, lambda { |net| joins(:site).where("alarm.mac_address = site.mac_address").where('site.network_id=?', net) }

但问题似乎是rails#join假设两个表都在同一个数据库中,而不检查每个表正在使用的连接。

4

1 回答 1

0

所以当你知道如何时,答案很简单......

ActiveRecord::Base 有一个table_name_prefix方法,只要在查询中使用它,就会在表名上添加一个特定的前缀。如果重新定义这个方法在表名前面加上数据库名,生成的SQL会被强制使用正确的数据库

因此,在我最初的问题中,我们将以下方法定义添加到表警报、站点和网络(以及其他任何需要的地方)中

def self.table_name_prefix
   self.connection.current_database+'.'
end

然后我们可以使用范围轻松构建连接

scope :network_alarms, lambda { |net| joins(:site => :network).where('site.network_id=?', net) }

感谢srosenhammer的原始答案(这里:Rails 3 - Multiple database with joins condition

史蒂夫

于 2012-11-19T19:49:47.460 回答