with tutorial framework español djangoproject desde con cero applications ruby-on-rails ruby database migration

ruby-on-rails - framework - tutorial django



Usar Rails Migration en una base de datos diferente a la "producción" o "desarrollo" estándar (19)

Tengo un proyecto de carriles en ejecución que define la producción estándar :,: desarrollo y: conexiones DB de prueba en config / database.yml

Además, tengo un quiz_development: y quiz_production: definición que apunta a un host / db / usuario / contraseña differnet

Mi objetivo ahora es definir una migración que use " quiz_#{RAILS_ENV }` "como su configuración de base de datos.

Lo que he intentado (y fallé):

  • Establecer ActiveRecord :: Base.connection en el archivo de Migración
  • Cambiar la tarea db: migrate en rieles para establecer ActiveRecord :: Base.connection allí

Pregunta:

¿Cómo puedo hacer que rake db: migrate use esa otra definición de base de datos?

Gracias, Frank


¿Has intentado usar quiz_development como RAILS_ENV (en lugar de intentar que use "quiz_#{RAILS_ENV}" )?

RAILS_ENV=quiz_development rake db:migrate


Además de ejecutar una migración en un entorno diferente, también quiero los esquemas en archivos separados. Puedes hacer esto desde la línea de comando:

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

Pero me gusta el enfoque personalizado de la tarea de rake, así que puedo escribir esto en su lugar:

rake db:with[quiz_development, db:migrate]

Aquí está la tarea 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


Basado en la respuesta 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

Uso:

ActiveRecord.on_connection "sdmstore_#{Rails.env}" do Widget.delete_all end


Debe definir las otras bases de datos / entornos en / config / environments.

Después de eso, puede usar el siguiente comando para migrar ese entorno específico.

rake db:migrate RAILS_ENV=customenvironment


En Rails 3.2, no es posible agregar un método de conexión a su migración. Entonces todas las respuestas como

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

simplemente no funcionará (no se puede down , no funciona con change , conexión perdida, etc.) La razón para esto es que la clase ActiveRecord :: Migration and Migrator tiene conexiones codificadas de forma rígida en ActiveRecord :: Base en all over the place

Afortunadamente, esta publicación me señaló este ticket que tiene una buena solución, es decir, que reemplaza la tarea de rake real.

Terminé usando una tarea de rake ligeramente diferente para poder ser específico acerca de las migraciones que ejecuto en la base de datos diferente (estábamos tratando de admitir múltiples versiones db):

Aquí está mi 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

Esto nos permite poner las migraciones específicas a una base de datos en su propio subdirectorio (nine_four / migrations en lugar de db / migrations). También proporciona a cada base de datos un aislamiento total en términos de sus versiones de esquema y migración. El único inconveniente es tener dos tareas de rake para ejecutar (db: migrate y nine_four: db: migrate).


Funcioné creando clases de conectores separadas para diferentes bases de datos y usándolas en las migraciones.

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

Podemos definir estas clases de conector en inicializadores.

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

ActiveRecord :: Base mantiene un grupo de conexiones que es un hash indexado por la clase. Lea más aquí . Entonces, usar clases separadas para conexiones separadas nos protege del error de conexión cerrada.

Además, el uso de up y down lugar de change nos permite deshacer la migración sin ningún problema. Todavía no he descubierto la razón de esto.


Hay una respuesta mucho más fácil. Agregue esto a su migración:

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

Eso es para Rails 3.1. Para Rails 2.X o 3.0 es una función de clase en su lugar (por ejemplo, def self.connection )


He encontrado una gran manera limpia de hacer esto:

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


Hola. Estuve investigando esto por unos días y terminé con esta solución, solo quería compartirla, podría ayudar a alguien.

Aquí la esencia completa para ello. https://gist.github.com/rafaelchiti/5575309 Tiene detalles y explicación. Pero encuentra a continuación más detalles si los necesitas.

El enfoque se basa en agregar un espacio de nombres a las tareas de rake ya conocidas db: migrate, db: create, db: drop y realizar esas tareas con una base de datos diferente. Y luego, al agregar una clase base de registro activo (AR) para la conexión basada en la configuración del nuevo archivo database.yml. De esta forma no es necesario hackear las migraciones con la conexión y se obtiene una estructura de directorios limpia.

Tu estructura terminará así

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)

Luego, en su código puede crear una clase base y leer la configuración desde este nuevo archivo database.yml y conectarse solo a los modelos que heredan de esa clase base AR. (ejemplo en la esencia).

¡Mejor!.


Lo tengo para trabajar con el siguiente código.

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

Fue necesario restablecer la conexión para que escribiera la migración en la tabla schema_migrations para que rake no intente volver a ejecutar la migración la próxima vez. Esto supone que desea que la tabla schema_migrations en la configuración de base de datos predeterminada realice un seguimiento de las migraciones registradas en el control de versión para el proyecto correspondiente.

No pude obtener la migración hacia abajo para trabajar.


Para Rails 3.2, esto es lo que hicimos, funciona con la migración hacia arriba y hacia abajo:

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


Puede usar esta versión, que también admite 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


Recientemente luché con el mismo problema. El objetivo era dividir una tabla de historias en una base de datos diferente, ya que ya era muy grande y seguía creciendo muy rápidamente.

Empecé a tratar de resolverlo haciendo ActiveRecord::Base.establish_connection(:history_database) , pero no pude obtener ninguna variación de esa manera para trabajar sin que se cerrara la conexión. Entonces finalmente descubrí la solución a continuación.

En el modelo de Historia después de hacer este cambio:

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

Pude hacer esto en la migración y funcionó perfectamente:

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

Esto creará la tabla en una base de datos diferente, pero modificará la tabla schema_migrations en la base de datos original para que la migración no vuelva a ejecutarse.


Siguiendo con @Bryan Larsen, si está utilizando una clase abstracta para adjuntar una serie de modelos a una base de datos diferente y desea migrar esquemas en ellos, puede hacer esto:

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

con un modelo configurado algo así como:

class Post < ReferenceData end

y

class ReferenceData < ActiveRecord::Base self.abstract_class = true establish_connection "reference_data_#{Rails.env}" end


También puede mover todas las migraciones relacionadas con el cuestionario a una subcarpeta separada en el directorio db / y luego agregar tareas de rake que reflejen la funcionalidad de migración normal, pero que busque las migraciones en ese subdirectorio. No súper elegante quizás pero funciona. Puede copiar y pegar las tareas de rake que ya están en rieles y simplemente modificarlas un poco.


Un poco tarde, pero hoy estaba lidiando con este problema y se me ocurrió esta tarea personalizada de rake:

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


si desea mostrar la publicación de WordPress en su sitio web de rieles y no desea usar la gema de conexión multimagia. puede usar el siguiente código para obtener los datos del blog de 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


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

Y:

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

Puede llamar a Artic.get_test_name para ejecutar.


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 coloca esto dentro de las config/initializers/ podrá hacer algo como esto:

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

Esto eliminará todos los widgets en el db de producción y se asegurará de que la conexión con los db env actuales de env se restablezca después de eso.

Si solo desea que esté disponible en sus migraciones, inserte la extensión de la clase ActiveRecord::Migration .