Wykorzystanie migracji Rails na innej bazie danych niż standardowa "produkcja" lub " rozwój"

Mam uruchomiony projekt rails, który definiuje standard production:,: development I: test dB-connections w config / database.yml

Dodatkowo mam quiz_development: i quiz_production: definicja wskazująca na różny host / db / user / password

Moim celem jest teraz zdefiniowanie migracji, która używa "quiz_#{RAILS_ENV}` " jako konfiguracji bazy danych.

Czego próbowałem (i zawiodłem):

  • Ustawienie ActiveRecord:: Base.połączenie w migracji plik
  • Zmiana zadania db: migrate w rails na ActiveRecord:: Base.połączenie tam

Pytanie:

Jak sprawić, by rake db: migrate używał innej definicji bazy danych?

Dzięki, Frank

Author: August Lilleaas, 2009-09-10

19 answers

Trochę za późno, ale miałem dziś do czynienia z tym problemem i wpadłem na takie niestandardowe zadanie grabie:

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
Author: Siu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-27 17:34:04

Jest o wiele łatwiejsza odpowiedź. Dodaj to do swojej migracji:

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

To dla Rails 3.1. Dla Rails 2.X lub 3.0 jest to funkcja klasy zamiast (np def self.connection)

 34
Author: Bryan Larsen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-11 05:15:40

Mam to do pracy z poniższym kodem.

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

Konieczne było ustawienie połączenia z powrotem, aby można było zapisać migrację do tabeli schema_migrations, aby rake nie próbował ponownie uruchomić migracji następnym razem. Zakłada to, że chcesz, aby tabela schema_migrations w domyślnej konfiguracji bazy danych śledziła migracje sprawdzone do kontroli wersji dla odpowiedniego projektu.

Nie udało mi się sprowadzić migracji do pracy.

 18
Author: Marlin Pierce,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-08 15:22:41

Należy zdefiniować inne bazy danych/środowiska w /config / environments.

Następnie możesz użyć następującego polecenia do migracji tego konkretnego środowiska.

rake db:migrate RAILS_ENV=customenvironment
 13
Author: Bitterzoet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-15 13:16:04

Idąc dalej od @Bryan Larsen, jeśli używasz klasy abstrakcyjnej do dołączania serii modeli do innej bazy danych i chciałbyś przenieść na nie Schematy, możesz to zrobić:

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

Z modelem ustawić coś takiego:

class Post < ReferenceData
end

I

class ReferenceData < ActiveRecord::Base
  self.abstract_class = true
  establish_connection "reference_data_#{Rails.env}"
end
 8
Author: bouchard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-20 03:31:17

Ostatnio zmagałem się z tym samym problemem. Celem było rozdzielenie tabeli historii na inną bazę danych, ponieważ była ona już tak duża i wciąż bardzo szybko rośnie.

Zacząłem próbować rozwiązać go, robiąc ActiveRecord::Base.establish_connection(:history_database), ale nie mogłem uzyskać żadnych wariantów tego sposobu, aby działać bez zamknięcia połączenia. W końcu odkryłem rozwiązanie poniżej.

W modelu historii po dokonaniu tej zmiany:

class History < ActiveRecord::Base

  # Directs queries to a database specifically for History
  establish_connection :history_database

  ...
end

Udało mi się to zrobić w migracji i to działa idealnie:

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

  def down
    History.connection.drop_table :histories
  end
end

Spowoduje to utworzenie tabeli w innej bazie danych, ale zmodyfikuje tabelę schema_migrations w oryginalnej bazie danych, aby migracja nie została uruchomiona ponownie.

 8
Author: MTarantini,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-15 15:41:44

Hej grzebałem w tym od kilku dni i skończyło się na tym rozwiązaniu, chciałem się nim podzielić, może komuś pomoże.

Tutaj cała istota tego. https://gist.github.com/rafaelchiti/5575309 Zawiera szczegóły i wyjaśnienia. Ale znajdź poniżej więcej szczegółów, jeśli ich potrzebujesz.

Podejście opiera się na dodaniu przestrzeni nazw do znanych już zadań rake db:migrate, db:create, db:drop i wykonaniu tych zadań z inną bazą danych. A potem w dodawaniu Klasa base active record (AR) do łączenia w oparciu o konfigurację nowej bazy danych.plik yml. W ten sposób nie musisz hakować migracji za pomocą połączeń i uzyskasz czystą strukturę katalogów.

Twoja struktura skończy tak

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)

Następnie w kodzie możesz utworzyć klasę bazową i odczytać konfigurację z nowej bazy danych.plik yml i połączyć się z nim tylko na modelach dziedziczących z tej klasy bazowej AR. (przykład w gist).

Najlepszy!.
 7
Author: Rafael,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-14 12:06:51

Dla Rails 3.2, to jest to, co zrobiliśmy, działa z migracją w górę iw dół:

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
Author: zephyr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-23 22:24:33
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

Jeśli umieścisz to w config/initializers/ będziesz mógł zrobić coś takiego:

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

Spowoduje to usunięcie wszystkich widżetów w DB produkcji i upewni się, że połączenie z bieżącym dB Rails env zostanie przywrócone po tym.

Jeśli chcesz tylko udostępnić go w swojej migracji INSEAD rozszerz klasę ActiveRecord::Migration.

 5
Author: TheDeadSerious,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-03 11:50:52

W rails 3.2 dodanie metody połączenia do migracji nie działa. Więc wszystkie odpowiedzi jak

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

Po prostu nie działa (nie może down, nie działa z change, połączenie utracone, itp.) Powodem tego jest to, że Klasy migracji i migracji ActiveRecord mają połączenia zakodowane na twardo do ActiveRecord:: Base all over na miejsce .

Na szczęście Ten post wskazał mi ten bilet który ma dobry rozwiązanie, a mianowicie nadpisanie rzeczywistegozadania rake .

Skończyło się na użyciu nieco innego zadania rake, więc mogłem być konkretny na temat migracji, które uruchamiam na innej bazie danych (staraliśmy się obsługiwać wiele wersji db):

Oto mój lib / zadanie / baza danych.grabie

# 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

To pozwala nam umieścić migracje specyficzne dla jednej bazy danych w ich własnym podkatalogu(nine_four/migrations zamiast db / migrations). daje też każdej bazie całkowitą izolację w warunki ich schematów i wersji migracyjnych. jedynym minusem jest posiadanie dwóch zadań rake do uruchomienia(db: migrate i nine_four:db:migrate).

 4
Author: Ryan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:09

Oprócz uruchamiania migracji w innym środowisku, chcę również schematy w osobnych plikach. Możesz to zrobić z linii poleceń:

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

Ale podoba mi się niestandardowe podejście do zadań rake, więc mogę zamiast tego wpisać:

rake db:with[quiz_development, db:migrate]

Oto zadanie grabie:

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
Author: Eric Dobbs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-30 20:40:19

Znalazłem świetny czysty sposób, aby to zrobić:

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
Author: just.jules,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-29 13:59:58
class Article < ActiveRecord::Base

    ActiveRecord::Base.establish_connection(
      :adapter  => "mysql2",
      :host     => "localhost",
      :username => "root",
      :database => "test"
    )
end

I:

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
Możesz zadzwonić do Artic.get_test_name w celu wykonania.
 1
Author: Santosh Singh-Bagadhbilla,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-02 18:19:56

Możesz użyć tej wersji, która obsługuje również 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
Author: nlsrchtr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-09 10:36:03

Czy próbowałeś użyć quiz_development jako rails_env (zamiast próbować zmusić go do użycia "quiz_#{RAILS_ENV}")?

RAILS_ENV=quiz_development rake db:migrate
 0
Author: hgmnz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-14 12:06:58

Możesz także przenieść wszystkie migracje związane z quiz_ do osobnego podfolderu w katalogu db/, a następnie dodać zadania rake odzwierciedlające funkcjonalność migracji regularnej, która szuka migracji w tym podkatalogu. Może nie jest zbyt elegancki, ale działa. Możesz skopiować i wkleić zadania rake już w rails i po prostu trochę je zmodyfikować.

 0
Author: ealdent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-14 12:21:42

Na podstawie odpowiedzi @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

Użycie:

ActiveRecord.on_connection "sdmstore_#{Rails.env}" do
  Widget.delete_all
end
 0
Author: Pratik Khadloya,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-13 15:42:05

Jeśli chcesz wyświetlić wpis wordpress na swojej stronie rails i nie chcesz używać klejnotu połączenia z magią. możesz użyć poniższego kodu, aby uzyskać dane z bloga wordpress.

 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
Author: Santosh Singh-Bagadhbilla,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-02 19:15:37

Stworzyłem osobne klasy konektorów dla różnych baz danych i wykorzystałem je w migracjach.

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

Możemy zdefiniować te klasy konektorów w inicjalizatorach.

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

ActiveRecord:: Base przechowuje pulę połączeń, która jest Hashem indeksowanym przez klasę. Czytaj więcej tutaj . Tak więc używanie oddzielnych klas dla oddzielnych połączeń chroni nas przed błędem zamkniętego połączenia.

Również użycie up i down zamiast change pozwala na cofnięcie migracja bez problemu. Nadal Nie wiem dlaczego.

 0
Author: gauravm31,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-28 10:45:59