J'ai un projet Rails en cours d'exécution qui définit la production standard:,: développement et: test des connexions DB dans config/database.yml
De plus, j'ai un quiz_development: et quiz_production: définition pointant vers un hôte/db/utilisateur/mot de passe différent
Mon objectif est maintenant de définir une migration qui utilise "quiz_#{Rails_ENV
}` "comme configuration de base de données.
Ce que j'ai essayé (et échoué):
Question:
Comment puis-je faire en sorte que rake db: migrate utilise cette autre définition de base de données?
Merci, .__ Frank
Un peu tard, mais je traitais ce problème aujourd'hui et je suis arrivé avec cette tâche de rake personnalisée:
namespace :db do
desc "Apply db tasks in custom databases, for example rake db:alter[db:migrate,test-es] applies db:migrate on the database defined as test-es in databases.yml"
task :alter, [:task,:database] => [:environment] do |t, args|
require 'activerecord'
puts "Applying #{args.task} on #{args.database}"
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations[args.database])
Rake::Task[args.task].invoke
end
end
Il y a une réponse beaucoup plus facile. Ajoutez ceci à votre migration:
def connection
ActiveRecord::Base.establish_connection("quiz_#{Rails.env}").connection
end
C'est pour Rails 3.1. Pour Rails 2.X ou 3.0, il s’agit plutôt d’une fonction de classe (par exemple, def self.connection
)
Je dois travailler avec le code suivant.
class AddInProgressToRefHighLevelStatuses < ActiveRecord::Migration
def connection
@connection = ActiveRecord::Base.establish_connection("sdmstore_#{Rails.env}").connection
end
def change
add_column :ref_high_level_statuses, :is_in_progress, :boolean, :default => true
@connection = ActiveRecord::Base.establish_connection("#{Rails.env}").connection
end
end
Il était nécessaire de rétablir la connexion pour qu'il écrive la migration dans la table schema_migrations afin que rake n'essaye pas de réexécuter la migration la prochaine fois. Cela suppose que vous souhaitiez que la table schema_migrations de la configuration de base de données par défaut garde la trace des migrations archivées dans le contrôle de version du projet correspondant.
Je ne pouvais pas obtenir la migration vers le bas au travail.
Vous devez définir les autres bases de données/environnements dans/config/environnements.
Après cela, vous pouvez utiliser la commande suivante pour migrer cet environnement spécifique.
rake db:migrate Rails_ENV=customenvironment
J'ai récemment lutté avec le même problème. Le but était de scinder une table d'histoires en une autre base de données, car elle était déjà très grande et continuait de croître très rapidement.
J'ai commencé à essayer de le résoudre en faisant ActiveRecord::Base.establish_connection(:history_database)
, mais je ne pouvais faire fonctionner aucune variante de cette façon sans que la connexion soit fermée. Enfin, j'ai découvert la solution ci-dessous.
Dans le modèle d'historique après avoir effectué ce changement:
class History < ActiveRecord::Base
# Directs queries to a database specifically for History
establish_connection :history_database
...
end
J'ai pu faire cela dans la migration et cela a parfaitement fonctionné:
class CreateHistoriesTableInHistoryDatabase < ActiveRecord::Migration
def up
History.connection.create_table :histories do |t|
...
end
end
def down
History.connection.drop_table :histories
end
end
Cela créera la table dans une base de données différente, mais modifiera la table schema_migrations dans la base de données d'origine pour que la migration ne s'exécute plus.
Dans le prolongement de @Bryan Larsen, si vous utilisez une classe abstraite pour attacher une série de modèles à une base de données différente et souhaitez migrer des schémas sur ces derniers, procédez comme suit:
class CreatePosts < ActiveRecord::Migration
def connection
Post.connection
end
def up
...
end
end
avec un modèle mis en place quelque chose comme:
class Post < ReferenceData
end
et
class ReferenceData < ActiveRecord::Base
self.abstract_class = true
establish_connection "reference_data_#{Rails.env}"
end
Hey, je me suis plongé dans cette affaire pendant quelques jours et je me suis retrouvé avec cette solution, je voulais juste la partager, cela pourrait aider quelqu'un.
Voici le Gist complet pour cela. https://Gist.github.com/rafaelchiti/5575309 Il contient des détails et des explications. Mais trouvez ci-dessous plus de détails si vous en avez besoin.
L'approche consiste à ajouter un espace de noms aux tâches rake déjà connues, db: migrate, db: create, db: drop et à effectuer ces tâches avec une base de données différente. Et ensuite, en ajoutant une classe d'enregistrement actif (AR) de base pour la connexion en fonction de la configuration du nouveau fichier database.yml. De cette façon, vous n'avez pas besoin de pirater les migrations avec des trucs de connexion et vous obtenez une structure de répertoire vierge.
Votre structure finira comme ça
config
|- database.yml
\- another_database.yml (using the same nomenclature of 'development', 'test', etc).
db
|- migrate (default migrate directory)
|- schema.rb
|- seed.rb
another_db
|- migrate (migrations for the second db)
|- schema.rb (schema that will be auto generated for this db)
|- seed.rb (seed file for the new db)
Ensuite, dans votre code, vous pouvez créer une classe de base, lire la configuration à partir de ce nouveau fichier database.yml et vous y connecter uniquement sur les modèles hérités de cette classe de base AR. (exemple dans le Gist).
Meilleur!.
Pour Rails 3.2, voici ce que nous avons fait, fonctionne avec la migration vers le haut et le bas:
class CreateYourTable < ActiveRecord::Migration
def connection
@connection ||= ActiveRecord::Base.connection
end
def with_proper_connection
@connection = YourTable.connection
yield
@connection = ActiveRecord::Base.connection
end
def up
with_proper_connection do
create_table :your_table do |t|
end
end
end
def down
with_proper_connection do
drop_table :your_table
end
end
end
module ActiveRecord::ConnectionSwitch
def on_connection(options)
raise ArgumentError, "Got nil object instead of db config options :(" if options.nil?
ActiveRecord::Base.establish_connection(options)
yield
ensure
ActiveRecord::Base.establish_connection ActiveRecord::Base.configurations[Rails.env]
end
end
ActiveRecord.send :extend, ActiveRecord::ConnectionSwitch
Si vous placez ceci dans config/initializers/
, vous pourrez faire quelque chose comme ceci:
ActiveRecord.on_connection ActiveRecord::Base.configurations['production'] do
Widget.delete_all
end
Cela supprimera tous les widgets de la base de production et garantira que la connexion à la base de données de l'environnement Rails actuel est rétablie par la suite.
Si vous souhaitez simplement le rendre disponible dans vos migrations, insead étend la classe ActiveRecord::Migration
.
En plus d'exécuter une migration dans un environnement différent, je souhaite également que les schémas soient dans des fichiers séparés. Vous pouvez le faire depuis la ligne de commande:
Rails_ENV=quiz_development SCHEMA=db/schema_quiz_development.rb rake db:migrate
Mais j'aime bien l'approche de la tâche de rake personnalisée pour pouvoir taper ceci à la place:
rake db:with[quiz_development, db:migrate]
Voici la tâche de rake:
namespace :db do
desc "Run :task against :database"
task :with, [:database,:task] => [:environment] do |t, args|
puts "Applying #{args.task} to #{args.database}"
ENV['SCHEMA'] ||= "#{Rails.root}/db/schema_#{args.database}.rb"
begin
oldRailsEnv = Rails.env
Rails.env = args.database
ActiveRecord::Base.establish_connection(args.database)
Rake::Task[args.task].invoke
ensure
Rails.env = oldRailsEnv
end
end
end
J'ai trouvé un excellent moyen de faire ceci:
class CreateScores < ActiveRecord::Migration
class ScoresDB < ActiveRecord::Base
establish_connection("scores_#{Rails.env}")
end
def connection
ScoresDB.connection
end
def up
create_table :scores do |t|
t.text :account_id
t.text :offer
end
end
def down
drop_table :scores
end
end
Vous pouvez utiliser cette version, qui prend également en charge rake db:rollback
:
class ChangeQuiz < ActiveRecord::Migration
def connection
ActiveRecord::Base.establish_connection("quiz_#{Rails.env}").connection
end
def reset_connection
ActiveRecord::Base.establish_connection(Rails.env)
end
def up
# make changes
reset_connection
end
def self.down
# reverse changes
reset_connection
end
end
class Article < ActiveRecord::Base
ActiveRecord::Base.establish_connection(
:adapter => "mysql2",
:Host => "localhost",
:username => "root",
:database => "test"
)
end
Et:
class Artic < Aritcle
self.table_name = 'test'
def self.get_test_name()
query = "select name from testing"
tst = connection.select_all(query) #select_all is important!
tst[0].fetch('name')
end
end
Vous pouvez appeler Artic.get_test_name pour l'exécuter.
Basé sur la réponse de @ TheDeadSerious:
module ActiveRecord::ConnectionSwitch
def on_connection(connection_spec_name)
raise ArgumentError, "No connection specification name specified. It should be a valid spec from database.yml" unless connection_spec_name
ActiveRecord::Base.establish_connection(connection_spec_name)
yield
ensure
ActiveRecord::Base.establish_connection(Rails.env)
end
end
ActiveRecord.send :extend, ActiveRecord::ConnectionSwitch
Usage:
ActiveRecord.on_connection "sdmstore_#{Rails.env}" do
Widget.delete_all
end
Avez-vous essayé d'utiliser quiz_development en tant que Rails_ENV (au lieu d'essayer de le faire utiliser "quiz_#{Rails_ENV}"
)?
Rails_ENV=quiz_development rake db:migrate
Cela fonctionne en créant des classes de connecteur distinctes pour différentes bases de données et en les utilisant dans les migrations.
class AddExampleToTest < ActiveRecord::Migration
def connection
@connection = OtherDatabaseConnector.establish_connection("sdmstore_#{Rails.env}").connection
end
def up
add_column :test, :example, :boolean, :default => true
@connection = MainDatabaseConnector.establish_connection("#{Rails.env}").connection
end
def down
remove_column :test, :example
@connection = MainDatabaseConnector.establish_connection("#{Rails.env}").connection
end
end
Nous pouvons définir ces classes de connecteur dans les initialiseurs.
class MainDatabaseConnector < ActiveRecord::Base
end
class OtherDatabaseConnector < ActiveRecord::Base
end
ActiveRecord :: Base conserve un pool de connexions qui est un hachage indexé par la classe. Lire la suite ici . Donc, utiliser des classes séparées pour des connexions séparées nous protège de l'erreur de connexion fermée.
De plus, utiliser up
et down
au lieu de change
nous permet d’annuler la migration sans aucun problème. Je n'ai toujours pas compris la raison de cela.
Vous pouvez également déplacer toutes vos migrations liées à quiz_ dans un sous-dossier distinct du répertoire db /, puis ajouter des tâches rake reflétant la fonctionnalité de migration normale, mais qui recherchent les migrations dans ce sous-répertoire. Pas super élégant peut-être mais ça marche. Vous pouvez copier et coller les tâches rake déjà dans Rails et les modifier un peu.
si vous souhaitez afficher la publication wordpress sur votre site Web Rails et que vous ne voulez pas utiliser le joyau de la connexion multi-magique. vous pouvez utiliser le code ci-dessous afin d’obtenir les données de wordpress blog.
class Article < ActiveRecord::Base
ActiveRecord::Base.establish_connection(
:adapter => "mysql2",
:Host => "localhost",
:username => "root",
:database => "blog"
)
self.table_name = 'wp_posts'
def self.get_post_data()
query = "select name from testing"
tst = connection.select_all(query)
tst[0].fetch('name')
end
end