Using Rails Migration on different database than standard “production” or “development”

前端 未结 20 1326
借酒劲吻你
借酒劲吻你 2020-11-29 18:18

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

In addition I have a quiz_developm

相关标签:
20条回答
  • 2020-11-29 18:46

    In addition to running a migration in a different environment, I also want the schemas 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 custom rake task approach 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
    
    0 讨论(0)
  • 2020-11-29 18:46

    if you want to display the wordpress post to your rails website and you don't want to use mult-magic connection gem. you can use the below code in order to get the data from 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 讨论(0)
  • 2020-11-29 18:50

    Based on @TheDeadSerious's 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
    

    Usage:

    ActiveRecord.on_connection "sdmstore_#{Rails.env}" do
      Widget.delete_all
    end
    
    0 讨论(0)
  • 2020-11-29 18:53

    I recently struggled with the same problem. The goal was to split off a histories table to a different database since it was already so large and still growing very quickly.

    I started trying to resolve it by doing ActiveRecord::Base.establish_connection(:history_database), but could not get any variations of that way to work without the connection being closed. Then finally I discovered the 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 in the migration 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 the table in a different database, yet modify the schema_migrations table in the original database so the migration does not run again.

    0 讨论(0)
  • 2020-11-29 18:53

    I got this working by creating separate connector classes for different databases and using them in the 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
    

    We can define these connector classes in initializers.

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

    ActiveRecord::Base keeps a connection pool that is a hash indexed by the class. Read more here. So using separate classes for separate connections protects us from the closed connection error.

    Also, using up and down instead of change allows us to rollback the migration without any issue. Still haven't figured out the reason for this.

    0 讨论(0)
  • 2020-11-29 18:54

    Following on from @Bryan Larsen, if you're using an abstract Class to attach a series of models to a different database, and would like to migrate schemas on them, then you can do this:

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

    with a model set up something like:

    class Post < ReferenceData
    end
    

    and

    class ReferenceData < ActiveRecord::Base
      self.abstract_class = true
      establish_connection "reference_data_#{Rails.env}"
    end
    
    0 讨论(0)
提交回复
热议问题