0

アラーム、サイト、ネットワークの 3 つのモデルがあります。彼らは属している関係によって接続されていますが、異なるデータベースに住んでいます

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メソッドを使用するため)。そう

この結合を行うためのよりインテリジェントな方法はありますか。たとえば、joinandステートメントを使用してみました (これは、私が試した多くのバリエーションの 1 つです)。where

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

しかし、問題は、各テーブルが使用している接続をチェックせずに、レール#joinが両方のテーブルが同じデータベースにあると想定していることです。

4

1 に答える 1

0

方法がわかれば、答えは簡単です...

ActiveRecord::Base にはtable_name_prefix、クエリで使用されるたびにテーブル名に特定のプレフィックスを追加するメソッドがあります。このメソッドを再定義してテーブル名の前にデータベース名を追加すると、生成された SQL は正しいデータベースを使用するよう強制されます。

そのため、最初の質問では、次のメソッド定義をテーブル Alarm、Site、および Network (およびその他の必要な場所) に追加します。

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 - 複数のデータベースと結合条件)

スティーブ

于 2012-11-19T19:49:47.460 に答える