2

Je suis en train d'installer un has_many: à travers une relation entre deux modèles utilisateur et CustomerAccount par une autre jointure modèle AccountOwnership (utilisateurs et account_ownerships tables sont dans un db, disent DB1 et la table customer_accounts est dans db distant, disons db2).Rails: la mise en place association has_many_through entre les tables de différentes bases de données

Voici le code correspondant, qui met en place les 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 est correcte, bien que non représenté ici)

development: 
    reconnect: false 
    database: db1 
    pool: 5 

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

dans le script/console

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

a.user ## Returns the correct user 

a.company ## returns the correct CustomerAccount instance 

aussi

a.user.account_ownership ## returns a as anticipated 

mais

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

Le problème ici est que les tables "account_ownerships" et "utilisateurs" sont contenus dans une base de données par défaut (disons DB1), et la table "clients" est contenu dans une base de données différente (disons db2). Les connexions aux bases de données sont configurées correctement, mais pendant la recherche puisqu'il n'y a qu'un objet de connexion de base de données disponible, Rails essaie de trouver la base de données account_ownerships dans db2 et échoue donc.

Il ressemble à ma conception/logique pourrait être erronée parce que je ne vois pas un moyen de se connecter à deux bases de données différentes en utilisant la même connexion db, mais je serait ravi de voir s'il y a une solution de contournement, sans changer la conception. (Je suis réticent à changer la conception parce que db2 n'est pas sous mon contrôle)

Il semble que je puisse contourner ce problème en déplaçant ma table account_ownerships à DB2, mais ce n'est pas idéal pour moi au moins.

Existe-t-il d'autres mécanismes/schémas pour configurer cette association dans Rails.

Merci d'avance. M

Répondre

1

Solution:

Il semble que cela ne peut pas être réalisée par une association Rails magique, puisque c'est une limitation de base de tout mécanisme d'accès de base de données, y compris SQL premières.

Voici ce que je l'ai fait pour contourner le problème:

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 

Ceci fournit une approximation correcte comme indiqué:

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

AUSSI

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

Et nous avons besoin d'ajouter deux des méthodes d'instance au modèle account_ownership, afin de se rapprocher de comportement sociation

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 

Maintenant, nous pouvons faire

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

ET

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

ATTENTION: 1. Comme il n'y a pas de suppression en cascade fait sur le modèle de CustomerAccount, si les comptes sont supprimés , cela ne sera pas reflété dans la table account_ownership, donc cela peut donner lieu à de vilaines erreurs ActiveRecord :: RecordNotFound dans la méthode users.