Using Rails Migration in a different database than standard “production” or “development”,

I have a rails project that defines standard production :, development and: test DB connections in config / database.yml

Also, I have quiz_development: and quiz_production: definition pointing to host_database / db / user / password

My goal now is to define a Migration that uses " quiz_#{RAILS_ENV }` "as its database configuration.

What I tried (and could not):

  • Setting ActiveRecord :: Base.connection in the migration file
  • Changing db: migrate task in rails to install ActiveRecord :: Base.connection there

Question:

How can I make rake db: migrate use a different database definition?

Thanks Frank

+43
ruby database ruby-on-rails migration
Sep 10 '09 at 11:01
source share
19 answers

A little late, but today I ran into this problem, and I came up with this usual task:

 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 
+11
Nov 27 '09 at 17:34
source share

There it is much easier to answer. Add this to your migration:

 def connection ActiveRecord::Base.establish_connection("quiz_#{Rails.env}").connection end 

This is for Rails 3.1. For Rails 2.X or 3.0, a class function is used instead (for example, def self.connection )

+32
Mar 11 '12 at 5:15
source share

I got this to work with the following code.

 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 

It was necessary to establish a connection back in order to force it to write the migration to the schema_migrations table so that the rake would not try to restart the migration the next time. It is assumed that you want the schema_migrations table in the database configuration to monitor controlled migrations in version control for the corresponding project by default.

I was unable to migrate down.

+18
Jun 13 '12 at 17:53
source share

You must define other databases / environments in / config / environment.

After that, you can use the following command to migrate this particular environment.

 rake db:migrate RAILS_ENV=customenvironment 
+13
Sep 15 '09 at 13:16
source share

Hey, I delved into this for a few days, and I ended up with this solution, just wanted to share it, it can help someone.

Here is the full meaning for him. https://gist.github.com/rafaelchiti/5575309 This one has details and an explanation. But find below more detailed information if you need them.

The approach is based on adding a namespace to the already known rake tasks db: migrate, db: create, db: drop and perform these tasks with another database. And then add an Active Active Record (AR) class to connect based on the configuration of the new database.yml file. This way you don’t have to hack migrations with connections, and you get a clean directory structure.

Your structure will end as follows

 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) 

Then in your code, you can create a base class and read the configuration from this new database.yml file and connect to it only on models that inherit from this base AR class. (example mainly).

Best !.

+7
May 14 '13 at 12:06
source share

For Rails 3.2, this is what we did, working with up and down migration:

 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 
+7
Sep 23 '13 at 22:24
source share

Following @Bryan Larsen, if you use an abstract class to attach a series of models to another database and want to transfer the schemas to them, you can do this:

 class CreatePosts < ActiveRecord::Migration def connection Post.connection end def up ... end end 

with the model, create something like:

 class Post < ReferenceData end 

and

 class ReferenceData < ActiveRecord::Base self.abstract_class = true establish_connection "reference_data_#{Rails.env}" end 
+7
Oct 20 '13 at 3:31 on
source share

I recently struggled with the same issue. The goal was to share the story table with another database, as it was already so large and still developing very fast.

I started trying to resolve this by running ActiveRecord::Base.establish_connection(:history_database) , but I could not get any variants of this method to work without closing the connection. Then finally I found a solution below.

In the History model, after making this change:

 class History < ActiveRecord::Base # Directs queries to a database specifically for History establish_connection :history_database ... end 

I was able to do this during the migration process and it worked perfectly:

 class CreateHistoriesTableInHistoryDatabase < ActiveRecord::Migration def up History.connection.create_table :histories do |t| ... end end def down History.connection.drop_table :histories end end 

This will create a table in another database, but modify the schema_migrations table in the source database so that the migration does not happen again.

+6
Dec 15 '15 at 15:20
source share
 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 

If you put it inside config/initializers/ , you can do something like this:

 ActiveRecord.on_connection ActiveRecord::Base.configurations['production'] do Widget.delete_all end 

This will remove all the widgets on the production database and then restore the connection with the current Rails env db.

If you just want it to be available in your migrations, extend the ActiveRecord::Migration class.

+5
Feb 03 '12 at 11:50
source share

In rails 3.2, adding a connection method to your migration does NOT work. So all the answers are kind of

 def connection @connection ||= ActiveRecord::Base.establish_connection end 

just doesn't work (can't down , doesn't work with change , lost connection, etc.). The reason for this is because the ActiveRecord :: Migration and Migrator classes have hardcoded connections to ActiveRecord :: Base all through place .

Fortunately, this post pointed me to this ticket , which has a good solution, namely redefining the actual rake task .

In the end, I used a slightly different rake task so that I could be specific regarding the migration I was running in a different database (we tried to support several versions of db):

Here is my lib / task / database.rake

 # Augment the main migration to migrate your engine, too. task 'db:migrate', 'nine_four:db:migrate' namespace :nine_four do namespace :db do desc 'Migrates the 9.4 database' task :migrate => :environment do with_engine_connection do ActiveRecord::Migrator.migrate("#{File.dirname(__FILE__)}/../../nine_four/migrate", ENV['VERSION'].try(:to_i)) end end end end # Hack to temporarily connect AR::Base to your engine. def with_engine_connection original = ActiveRecord::Base.remove_connection ActiveRecord::Base.establish_connection("#{ Rails.env }_nine_four") yield ensure ActiveRecord::Base.establish_connection(original) end 

This allows us to transfer migrations into one database into our own subdirectory (nine_four / migrations instead of db / migrations). It also gives a general isolation of each database in terms of their schemas and migration versions. The only drawback is running two rake tasks (db: migrate and nine_four: db: migrate).

+4
Feb 13 '15 at 17:20
source share

In addition to doing the migration to another environment, I also want the schemas to be in separate files. You can do this from the command line:

 RAILS_ENV=quiz_development SCHEMA=db/schema_quiz_development.rb rake db:migrate 

But I like the user-friendly approach to the robbery task, so I can type this instead:

 rake db:with[quiz_development, db:migrate] 

Here's the rake task:

 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 
+2
Nov 30 '11 at 20:40
source share

I found a great way to do this:

 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 
+2
Oct 29 '15 at 13:59 on
source share
 class Article < ActiveRecord::Base ActiveRecord::Base.establish_connection( :adapter => "mysql2", :host => "localhost", :username => "root", :database => "test" ) end 

and

 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 

You can call Artic.get_test_name to execute.

+1
Jun 02 '14 at 17:52
source share

You can use this version, which also supports 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 
+1
Sep 09 '15 at 10:36
source share

Have you tried using quiz_development as RAILS_ENV (instead of trying to use its "quiz_#{RAILS_ENV}" )?

 RAILS_ENV=quiz_development rake db:migrate 
0
Sep 14 '09 at 12:06
source share

You can also transfer all Quiz_ related migrations to a separate subfolder in the db / directory, and then add rake tasks that reflect the regular migration functions, but who are looking for migrations in this subdirectory. Not super-elegant, maybe, but it works. You can copy and paste rake tasks into the rails and modify them a bit.

0
Sep 14 '09 at 12:21
source share

Based on @TheDeadSerious answer:

 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 

Using:

 ActiveRecord.on_connection "sdmstore_#{Rails.env}" do Widget.delete_all end 
0
Jun 13 '13 at 15:42
source share

if you want to display a Wordpress message on the rails website and you don't want to use multi-line pearls. you can use the code below to get data from a 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 
0
Jun 02 '14 at 18:44
source share

I got this work by creating separate connector classes for different databases and using them in hyphenations.

 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 

We can define these connector classes in initializers.

 class MainDatabaseConnector < ActiveRecord::Base end class OtherDatabaseConnector < ActiveRecord::Base end 

ActiveRecord :: Base supports a connection pool, which is a hash indexed by a class. More details here . Therefore, the use of separate classes for individual connections protects us from closed connection errors.

In addition, using up and down instead of change allows us to roll back the migration without any problems. Still have not figured out the reason for this.

0
Dec 28 '17 at 10:45
source share



All Articles