Re: intentando entender el Rake::Task => poltergeist con el RAILS_ENV


#1

En el mismo hilo de “intentando entender el Rake::Task”.

Ahora, bueno de antes, pero presento mi duda ahora, me encuentro con
que al ejecutar Rake::Tasks[‘db:migrate’] las migraciones se ejecutan
en una u otra tabla dependiendo de cosas que a primera vista nada
tienen que ver.

Esta es mi rake de ejemplo:
desc “Run migrations”
task :run_migrations => [:environment] do
Rake::Task[‘db:create:all’].execute
Rake::Task[‘db:migrate’].execute
end

Como veis intenta ejecutar
$ rake db:create:all
$ rake db:migrate

Y es eso lo que hace pero las migraciones las corre en la db de test
en vez de la development como vemos a
continuación:
$ rake db:drop:all
(in /Users/fguillen/Documents/develop-ror/euruko_app)
$ rake init:run_migrations > /dev/null
$ ls -l db/
total 88
-rw-r–r-- 1 fguillen staff 0 26 ene 20:39 development.sqlite3
drwxr-xr-x 15 fguillen staff 510 26 ene 18:50 migrate
-rw-r–r-- 1 fguillen staff 0 26 ene 20:39 production.sqlite3
-rw-r–r-- 1 fguillen staff 5938 26 ene 20:39 schema.rb
-rw-r–r-- 1 fguillen staff 34816 26 ene 20:39 test.sqlite3

Como veis se ha cargado la db test pero las demás están a cero.

Ahora bien… si saco de la rake el Rake::Task[‘db:create:all’] ,
entonces la migración la corre en development:

desc “Run migrations”
task :run_migrations => [:environment] do
Rake::Task[‘db:migrate’].execute
end

$ rake db:drop:all
$ rake db:create:all
$ rake init:run_migrations > /dev/null
$ ls -l db/
total 88
-rw-r–r-- 1 fguillen staff 34816 26 ene 20:41 development.sqlite3
drwxr-xr-x 15 fguillen staff 510 26 ene 18:50 migrate
-rw-r–r-- 1 fguillen staff 0 26 ene 20:41 production.sqlite3
-rw-r–r-- 1 fguillen staff 5938 26 ene 20:41 schema.rb
-rw-r–r-- 1 fguillen staff 0 26 ene 20:41 test.sqlite3

Otra prueba curiosa es que si dejamos el db:create:all dentro de la
rake pero las dbs ya existían de antes tenemos que también ejecuta la
migración en la db de development:

desc “Run migrations”
task :run_migrations => [:environment] do
Rake::Task[‘db:create:all’].execute
Rake::Task[‘db:migrate’].execute
end

$ rake db:drop:all
$ rake db:create:all
$ rake init:run_migrations > /dev/null
db/development.sqlite3 already exists
db/production.sqlite3 already exists
db/test.sqlite3 already exists
$ ls -l db/
total 88
-rw-r–r-- 1 fguillen staff 34816 26 ene 20:43 development.sqlite3
drwxr-xr-x 15 fguillen staff 510 26 ene 18:50 migrate
-rw-r–r-- 1 fguillen staff 0 26 ene 20:43 production.sqlite3
-rw-r–r-- 1 fguillen staff 5938 26 ene 20:43 schema.rb
-rw-r–r-- 1 fguillen staff 0 26 ene 20:43 test.sqlite3

Entonces al parecer lo que pasa es que ‘db:create:all’ modifica la
RAILS_ENV y la deja con valor ‘test’ entonces cuando llega
‘db:migrate’ ejecuta la migración en test.

He intentado, siguiendo las instrucciones de javi, a hacer esto:

desc “Run migrations”
task :run_migrations => [:environment] do
Rake::Task[‘db:create:all’].execute
ENV[‘RAILS_ENV’]=‘development’
Rake::Task[‘db:migrate’].execute
end

Pero nada :confused:

Tampoco esto
desc “Run migrations”
task :run_migrations => [:environment] do
Rake::Task[‘db:create:all’].execute
RAILS_ENV=‘development’
Rake::Task[‘db:migrate’].execute
end

Pues eso… que ni idea que puedo probar ahora… ¿algún capote? :slight_smile:

Saludos
f.


#2

Entonces al parecer lo que pasa es que ‘db:create:all’ modifica la
RAILS_ENV y la deja con valor ‘test’ entonces cuando llega
‘db:migrate’ ejecuta la migración en test.

sin ver el fuente tiene pinta de los conflictos de variables, sí… no
tengo ni idea de si colará, pero por probar

env_before=ENV.dup
Rake::Task[‘db:create:all’].execute
ENV=env_before
Rake::Task[‘db:migrate’].execute

Si ENV no está protegido de alguna forma rara, eso debería ejecutar la
segunda rake con el mismo entorno que la primera

y si no, toca leer el código de las rake de Active Record.

suerte,


javier ramírez

…i do ruby on rails development in madrid, spain, at
http://www.aspgems.com
…you can find out more about me on http://formatinternet.wordpress.com
and http://workingwithrails.com/person/5987-javier-ramirez


#3

env_before=ENV.dup

me ha entrado la curiosidad del dup sobre ENV y no va bien porque es un
singleton y el dup no lo hace bien, el clone te devuelve lo mismo y el
Marshal.dump no lo sabe serializar. Pero se puede hacer un volcado tal
que así

entries_before = ENV.entries
Rake::Task[‘db:create:all’].execute
entries_before.each {|en| ENV[en.first]=en.last}
Rake::Task[‘db:migrate’].execute

Lo de los rake no lo he probado… pero sí he probado que el ENV se
restaura con esto.

Con el ENV.entries consigues un array con las entradas, que luego
restauras antes de la segunda tarea. El punto débil aquí sería si la
tarea de antes hace set de alguna variable que no estuviera previamente,
porque con esto esas variables no se restaurarían. Si ese fuera el caso,
el reset habría que hacerlo iterando por ENV, comparando con
entries_before, y eliminando las que se hubieran añadido.

Bueno… no me pico más con esto :wink: ciao!


javier ramírez

…i do ruby on rails development in madrid, spain, at
http://www.aspgems.com
…you can find out more about me on http://formatinternet.wordpress.com
and http://workingwithrails.com/person/5987-javier-ramirez


#4

2009/1/26 javier ramirez removed_email_address@domain.invalid:

Rake::Task[‘db:create:all’].execute

Supongo que “test” es el último environment en database.yml.

Según se puede ver en el código, db:create:all itera por cada
environment de database.yml abriendo una conexión nueva a cada base de
datos, pero si mal no veo nunca la cierra, por lo que al realizar la
siguiente tarea utiliza la última conexión abierta, es decir ‘test’.
Claramente es un bug en Rails.

Una posible solución entre las dos tareas poner (no lo he probado):

ActiveRecord::Base.connection.disconnect!
ActiveRecord::Base.establish_connection(env[‘RAILS_ENV’])

Creo que eso conseguiría lo que quieres.

Suerte.


#5

El día 26 de enero de 2009 21:02, javier ramirez
removed_email_address@domain.invalid
escribió:> Rake::Task[‘db:create:all’].execute

ENV=env_before
Rake::Task[‘db:migrate’].execute

Si ENV no está protegido de alguna forma rara, eso debería ejecutar la
segunda rake con el mismo entorno que la primera

peta:

~/Documents/develop-ror/euruko_app(master) $ rake init:run_migrations
–trace
(in /Users/fguillen/Documents/develop-ror/euruko_app)
** Invoke init:run_migrations (first_time)
** Invoke environment (first_time)
** Execute environment
** Execute init:run_migrations
** Execute db:create:all
db/development.sqlite3 already exists
db/production.sqlite3 already exists
db/test.sqlite3 already exists
** Execute db:migrate
rake aborted!
undefined method `[]’ for #Object:0x1ef125c
/Library/Ruby/Gems/1.8/gems/rails-2.2.2/lib/tasks/databases.rake:110

y si no, toca leer el código de las rake de Active Record.

Pues sí… gracias javi… seguiré informando por aquí

Saludos
f.


#6

El día 26 de enero de 2009 21:19, javier ramirez
removed_email_address@domain.invalid
escribió:> Rake::Task[‘db:migrate’].execute

Bueno… no me pico más con esto :wink: ciao!

Pues espero no seguir picándote y dejarte descansar :)… pero no chuta

He dado un paso más y he comprobado las diferencias en el ENV antes y
despúes de la llamada a db:create:all. y … ahí no está el problema
pues son exactamente iguales:

desc “Run migrations”
task :run_migrations2 => [:environment] do
entries_before = ENV.entries
Rake::Task[‘db:create:all’].execute
entries_before.each do |en|
puts “cambio: #{ENV[en.first]} => #{en.last}” if ENV[en.first] !=
en.last
end
Rake::Task[‘db:migrate’].execute
end

No devuelve ningún cambio :confused:

Siguiendo tu consejo anterior y mirando el código estoy viendo que el
create:all recorre todas las configuraciones e invoca a:

        ActiveRecord::Base.establish_connection(config)
        ActiveRecord::Base.connection

Por lo que manda al traste la conexión que haya hecho el :environment
y se queda con la última… que, advina por donde, es la ‘test’.

Entonces al llegar la db:migrate pilla la conexión que esté activa que
casualmente es la ‘test’ y eso es lo que está pasando…

Ahora a ver como puedo forzar este comportamiento para que pille la
conexión relativa al environment ‘development’… y esta es la primera
aproximación:
desc “Run migrations”
task :run_migrations2 => [:environment] do
Rake::Task[‘db:create:all’].execute

config = ActiveRecord::Base.configurations[RAILS_ENV]
ActiveRecord::Base.establish_connection(config)
ActiveRecord::Base.connection

Rake::Task['db:migrate'].execute

end

Donde RAILS_ENV… lo podemos sustituir por ‘development’ o lo que
queramos.

… fin?

:slight_smile:

Graaaacias

f.


#7

El día 26 de enero de 2009 21:23, Daniel R.
Troitiñoremoved_email_address@domain.invalid
escribió:>> env_before=ENV.dup

Una posible solución entre las dos tareas poner (no lo he probado):

ActiveRecord::Base.connection.disconnect!
ActiveRecord::Base.establish_connection(env[‘RAILS_ENV’])

Creo que eso conseguiría lo que quieres.

Suerte.

Joer Dani… el más rápido del oeste rails :stuck_out_tongue_winking_eye:

f.