Così vi volete connettere a più database eh? Cosa siete, pazzi? :)
Naturalmente ci sono pro e contro su questo approccio. Io vi mostrerò come è fatto prima, poi lascierò a voi decidere se è realmente quello che volete fare.
Questa guida vi spiegherà solamente come determinare a quale database connettervi per request.
Questo differisce dal default in cui ogni applicazione rails utilizza soltanto un database di produzione. In questo modo, avete soltanto bisogno di cambiare il vostro file config/database.yml e sarete pronti per partire. Con più database, questo non è più accettabile.
app/controllers/abstract_application.rb definisce una classe chiamata \AbstractApplicationController. Tutti gli altri controllers creati dall’utente ereditano da questo. Andremo a posizionare un before_filter in questa classe per poterci inserire davanti al normale funzionamento di connessione al db. Poichè le connessioni \ActiveRecord funzionano su una base primo-arrivato/primo-servito, se siamo in grado di impostare il establish_connection prima che lo faccia il default, abbiamo vinto.
Capito? Bene.
class ==AbstractApplicationController== < ==ActionController==::Base
# qui, saltiamo di fronte alla gestione della coda di richieste
# per eseguire un metodo chiamato hijack_db
before_filter :hijack_db
# qui, andremo a stabilire manualmente una connessione
# al database
def hijack_db
# condizione completamente ridicola
is_odd = Time.now.hour % 2 == 1
# determina il nome del database
db_name = is_odd ? "dis_odd_db" : "dat_even_db"
# connettiamoci manualmente al db appropriato
<a href="http://wiki.rubyonrails.org/rails/pages/ActiveRecord" class="existingWikiWord">ActiveRecord</a>::Base.establish_connection(
:adapter => "mysql",
:host => "localhost",
:username => "mr_roboto",
:password => "secret_secret_i_got_a_secret",
:database => db_name
)
end
end
Naturalmente, vorreste avere una logica di determinazione del database migliore del fatto che l’ora sia dispari o meno. Potreste voler scambiare il database in base all’URL. Per esempio:
Forse state creando uno strumento per l’amministrazione di database con Rails (Wink, nudge) e avete bisogno di cambiare database in base ad una variabile query string (a.k.a. @params).
Forse, siete un web host e vi piacerebbe scegliere dinamicamente un database in base al sito del cliente che si sta caricando.
Qualsiasi sia la ragione, quel codice lo farà.
Come menzionato, ci sono pro e contro a questo approccio. Ora vi elencherò cosa posso e voglio lasciar decidere a voi.
David raccomanda fortemente l’approccio a database singolo (link?). Personalmente, concordo. \ActiveRecord è stato disegnato per uno scenario con un solo database. La vita è più semplice con un solo database. Propendete per l’approccio a database singolo a meno che non sappiate di averne realmente bisogno, oppure quando vi volete sentire semplicemente diversi. :)
— what-a-day con l’impagabile aiuto di #rubyonrails
Io ho una situazione in cui ho un database che controlla l’autenticazione per una serie di altre applicazioni (alcune rails… alcune no). Nella mia applicazione rails che utilizza questo schema di autenticazione ho il mio database.yml configurato per connettersi al database centrale di autenticazione (chiamato general_security). Poi, dal momento che il database specifico dell’applicazione rails vive sullo stesso server (username, password, host etc… tutti uguale cambia soltanto il nome del database) Gestisco il nome del database all’interno dei files modello.
class Mpq < ==ActiveRecord==::Base
def self.table_name() "mpq.mpqs" end
end
Questo ovviamente non funziona se username, password o l’host sono differenti. Notate anche che questo non funziona con PostgreSQL. — AustinMoody
Io ho riscontrato problemi utilizzando l’esempio precedente cosi com’è. Ho inserito i metodi hijack_db e before_filter nella mio application controller. Il problema era che facevo anche l’autenticazione e mi portavo un oggetto utente nella sessione. Così sono stato obbligato ad inserire “model :user” dentro il mio application controller. Questo ha messo in croce Rails perchè non aveva una connessione impostata.
Così quello che ho dovuto fare è stato quello di appiccicare la tabella Utenti nel DB per il mio ambiente (il DB che vorrei utilizzare se lo fissassi nella configurazione dei DB). E’ brutto, ma funziona. So I always hijack the DB before anything important happens, but I do need to provide tables for model objects carried in the session in the DB setup by database.yml.
—
Scaricate ActiveRecordCaveats per avere un’idea su come utilizzare database multipli con ereditarietà.
Controllate qui
per degli esempi di codice con database multipli.
Cosa fare se avete bisogno di connettervi ad un secondo (o più) database dalla vostra applicazione? Ad esempio, dovete utilizzare un database diverso da quello dell’applicazione per verificare una richiesta di autenticazione.
Aggiungete un nuovo record nel vostro file database.yml per ogni database. Per un database “security”, create questa voce per l’ambiente di sviluppo (development), di test (test), e di produzione (production).
security_development: adapter: postgresql database: security host: localhost username: uuuu password: xxxxxSuccessivamente, modificate il file ./config/environment.rb, appena sotto la linea ActiveRecord::Base.establish_connection aggiungete una linea per far connettere il vostro modello al nome utilizzato qui sopra.
La variabile RAILS_ENV contiene una di questi valori “development, "test” o “produzione”, in questo modo possiamo utilizzarla per differenziare la connessione in base all’ambiente.
Diciamo di avere un modello “Autorizzazione” che necessita di accedere ad una tabella nel database di sicurezza (security), per fare ciò aggiungiamo:
Autorizzazione.establish_connection "security_#{RAILS_ENV}��?Dubbi: Dobbiamo far questo per ogni tabella che non si trova nel database di applicazione e a cui abbiamo bisogno di accedere? Creerebbe connessioni multiple oppure creerebbe una cache delle connessioni in base al loro nome? Durante i tests il database security_test verrebbe cancellato e ricostruito?
Condividere Connessioni ActiveRecord Esterne di Dave Thomas che suggerisce questo:
class LegacyBase < ActiveRecord::Base self.abstract_class = true establish_connection “legacy_#{RAILS_ENV}” end class LegacyOrder < LegacyBase … end class LegacyLineItem < LegacyBase … endNotate il trucco utilizzato per impedire ad ActiveRecord di cercare il LegacyBase nel DB, contrassegnandola come classe astratta.
ActiveRecord::Base.configurations sembra non essere documentata. Può essere utilizzata per sovrascrivere soltanto il nome del database, ma mantenendo lo stesso host e le stesse informazioni di login. Per esempio:
config = ActiveRecord::Base.configurations[RAILS_ENV] class LegacyModel < ActiveRecord::Base establish_connection ( :database => “qualcheAltroDatabase”, :adapter => config‘adapter’, :username => config‘username’, … ) endQuesto potrebbe ritornare utile se sapete che il database che state per utilizzare per memorizzare i dati si trova sullo stesso host ed utilizza le stesse informazioni. (Oppure, se avete bisogno di conoscere le informazioni riguardo la vostra configurazione corrente di accesso al database per altri scopi)
Di seguito spiego come ho fatto in modo che le fixtures utilizzino il database appropriato. Tenete a mente che ci potrebbe essere una maniera migliore per fare ciò. Il nome della mia tabella è ‘parole’ con un modello chiamato Parola e nel file Parola.rb ho
Parola.establish_connection(:genMarkov)
Ora nel nostro unit_test anzichè utilizzare:
fixtures :paroleutilizziamo:
def setup Fixtures.create_fixtures(File.join(RAILS_ROOT, ‘test’, ’fixtures’), ’parole’) { Parola.connection } endcategory:Howto
Bath and Shower
Fragrance
Gift Sets
Hair Care
Makeup
Men’s Grooming
Shaving and Hair Removal
Skin Care
Tools and Accessories
Baby Apparel
Baby Bathing & Skin Care
Baby Bedding
Baby Car Seats
Baby Diapering
Baby Feeding
For Moms
Baby Furniture
Baby Gear
Baby Gifts
Baby Health & Baby Care
Nursery Décor
Potty Training
Baby Safety
Baby Strollers
Così vi volete connettere a più database eh? Cosa siete, pazzi? :)
Naturalmente ci sono pro e contro su questo approccio. Io vi mostrerò come è fatto prima, poi lascierò a voi decidere se è realmente quello che volete fare.
Questa guida vi spiegherà solamente come determinare a quale database connettervi per request.
Questo differisce dal default in cui ogni applicazione rails utilizza soltanto un database di produzione. In questo modo, avete soltanto bisogno di cambiare il vostro file config/database.yml e sarete pronti per partire. Con più database, questo non è più accettabile.
app/controllers/abstract_application.rb definisce una classe chiamata \AbstractApplicationController. Tutti gli altri controllers creati dall’utente ereditano da questo. Andremo a posizionare un before_filter in questa classe per poterci inserire davanti al normale funzionamento di connessione al db. Poichè le connessioni \ActiveRecord funzionano su una base primo-arrivato/primo-servito, se siamo in grado di impostare il establish_connection prima che lo faccia il default, abbiamo vinto.
Capito? Bene.
class ==AbstractApplicationController== < ==ActionController==::Base
# qui, saltiamo di fronte alla gestione della coda di richieste
# per eseguire un metodo chiamato hijack_db
before_filter :hijack_db
# qui, andremo a stabilire manualmente una connessione
# al database
def hijack_db
# condizione completamente ridicola
is_odd = Time.now.hour % 2 == 1
# determina il nome del database
db_name = is_odd ? "dis_odd_db" : "dat_even_db"
# connettiamoci manualmente al db appropriato
<a href="http://wiki.rubyonrails.org/rails/pages/ActiveRecord" class="existingWikiWord">ActiveRecord</a>::Base.establish_connection(
:adapter => "mysql",
:host => "localhost",
:username => "mr_roboto",
:password => "secret_secret_i_got_a_secret",
:database => db_name
)
end
end
Naturalmente, vorreste avere una logica di determinazione del database migliore del fatto che l’ora sia dispari o meno. Potreste voler scambiare il database in base all’URL. Per esempio:
Forse state creando uno strumento per l’amministrazione di database con Rails (Wink, nudge) e avete bisogno di cambiare database in base ad una variabile query string (a.k.a. @params).
Forse, siete un web host e vi piacerebbe scegliere dinamicamente un database in base al sito del cliente che si sta caricando.
Qualsiasi sia la ragione, quel codice lo farà.
Come menzionato, ci sono pro e contro a questo approccio. Ora vi elencherò cosa posso e voglio lasciar decidere a voi.
David raccomanda fortemente l’approccio a database singolo (link?). Personalmente, concordo. \ActiveRecord è stato disegnato per uno scenario con un solo database. La vita è più semplice con un solo database. Propendete per l’approccio a database singolo a meno che non sappiate di averne realmente bisogno, oppure quando vi volete sentire semplicemente diversi. :)
— what-a-day con l’impagabile aiuto di #rubyonrails
Io ho una situazione in cui ho un database che controlla l’autenticazione per una serie di altre applicazioni (alcune rails… alcune no). Nella mia applicazione rails che utilizza questo schema di autenticazione ho il mio database.yml configurato per connettersi al database centrale di autenticazione (chiamato general_security). Poi, dal momento che il database specifico dell’applicazione rails vive sullo stesso server (username, password, host etc… tutti uguale cambia soltanto il nome del database) Gestisco il nome del database all’interno dei files modello.
class Mpq < ==ActiveRecord==::Base
def self.table_name() "mpq.mpqs" end
end
Questo ovviamente non funziona se username, password o l’host sono differenti. Notate anche che questo non funziona con PostgreSQL. — AustinMoody
Io ho riscontrato problemi utilizzando l’esempio precedente cosi com’è. Ho inserito i metodi hijack_db e before_filter nella mio application controller. Il problema era che facevo anche l’autenticazione e mi portavo un oggetto utente nella sessione. Così sono stato obbligato ad inserire “model :user” dentro il mio application controller. Questo ha messo in croce Rails perchè non aveva una connessione impostata.
Così quello che ho dovuto fare è stato quello di appiccicare la tabella Utenti nel DB per il mio ambiente (il DB che vorrei utilizzare se lo fissassi nella configurazione dei DB). E’ brutto, ma funziona. So I always hijack the DB before anything important happens, but I do need to provide tables for model objects carried in the session in the DB setup by database.yml.
—
Scaricate ActiveRecordCaveats per avere un’idea su come utilizzare database multipli con ereditarietà.
Controllate qui
per degli esempi di codice con database multipli.
Cosa fare se avete bisogno di connettervi ad un secondo (o più) database dalla vostra applicazione? Ad esempio, dovete utilizzare un database diverso da quello dell’applicazione per verificare una richiesta di autenticazione.
Aggiungete un nuovo record nel vostro file database.yml per ogni database. Per un database “security”, create questa voce per l’ambiente di sviluppo (development), di test (test), e di produzione (production).
security_development: adapter: postgresql database: security host: localhost username: uuuu password: xxxxxSuccessivamente, modificate il file ./config/environment.rb, appena sotto la linea ActiveRecord::Base.establish_connection aggiungete una linea per far connettere il vostro modello al nome utilizzato qui sopra.
La variabile RAILS_ENV contiene una di questi valori “development, "test” o “produzione”, in questo modo possiamo utilizzarla per differenziare la connessione in base all’ambiente.
Diciamo di avere un modello “Autorizzazione” che necessita di accedere ad una tabella nel database di sicurezza (security), per fare ciò aggiungiamo:
Autorizzazione.establish_connection "security_#{RAILS_ENV}��?Dubbi: Dobbiamo far questo per ogni tabella che non si trova nel database di applicazione e a cui abbiamo bisogno di accedere? Creerebbe connessioni multiple oppure creerebbe una cache delle connessioni in base al loro nome? Durante i tests il database security_test verrebbe cancellato e ricostruito?
Condividere Connessioni ActiveRecord Esterne di Dave Thomas che suggerisce questo:
class LegacyBase < ActiveRecord::Base self.abstract_class = true establish_connection “legacy_#{RAILS_ENV}” end class LegacyOrder < LegacyBase … end class LegacyLineItem < LegacyBase … endNotate il trucco utilizzato per impedire ad ActiveRecord di cercare il LegacyBase nel DB, contrassegnandola come classe astratta.
ActiveRecord::Base.configurations sembra non essere documentata. Può essere utilizzata per sovrascrivere soltanto il nome del database, ma mantenendo lo stesso host e le stesse informazioni di login. Per esempio:
config = ActiveRecord::Base.configurations[RAILS_ENV] class LegacyModel < ActiveRecord::Base establish_connection ( :database => “qualcheAltroDatabase”, :adapter => config‘adapter’, :username => config‘username’, … ) endQuesto potrebbe ritornare utile se sapete che il database che state per utilizzare per memorizzare i dati si trova sullo stesso host ed utilizza le stesse informazioni. (Oppure, se avete bisogno di conoscere le informazioni riguardo la vostra configurazione corrente di accesso al database per altri scopi)
Di seguito spiego come ho fatto in modo che le fixtures utilizzino il database appropriato. Tenete a mente che ci potrebbe essere una maniera migliore per fare ciò. Il nome della mia tabella è ‘parole’ con un modello chiamato Parola e nel file Parola.rb ho
Parola.establish_connection(:genMarkov)
Ora nel nostro unit_test anzichè utilizzare:
fixtures :paroleutilizziamo:
def setup Fixtures.create_fixtures(File.join(RAILS_ROOT, ‘test’, ’fixtures’), ’parole’) { Parola.connection } endcategory:Howto
Bath and Shower
Fragrance
Gift Sets
Hair Care
Makeup
Men’s Grooming
Shaving and Hair Removal
Skin Care
Tools and Accessories
Baby Apparel
Baby Bathing & Skin Care
Baby Bedding
Baby Car Seats
Baby Diapering
Baby Feeding
For Moms
Baby Furniture
Baby Gear
Baby Gifts
Baby Health & Baby Care
Nursery Décor
Potty Training
Baby Safety
Baby Strollers