Como siempre, la menor chorrada se convierte en un cúmulo de lios. He abierto la clas ActiveRecord::Migration para añadirle un par de métodos, en concreto: add_foreign_key y remove_foreign_key Esto ha sido lo fácil.. un par de executes ahà dentro y fuera. ( para más detalles http://gist.github.com/136799 ) El lÃo ha venido al intentar un rake db:test:clone que pensé que cogÃa el estado de la db_development y la clonaba en db_test.. pero no es asà del todo.. al parecer lo que hace es coger el schema.rb y volcarlo en db_test. El problema es que mi monkey_patch no modifica el schema.rb para añadirle las lÃneas de add_foreign_key si alguna migración las ha invocado. Osea que el schema.rb está perfecto excepto que no ha incluido mis llamadas a add_foreign_key. Entonces mi pregunta es: ¿En que punto del código de Rails se vuelcan órdenes en schema.rb para poder hacer yo lo mismo? He rebuscado y tenemos por un lado: http://api.rubyonrails.org/classes/ActiveRecord/Migration.html Pero no veo donde accede a schema.rb Tenemos también: /Library/Ruby/Gems/1.8/gems/activerecord-2.3.2/lib/active_record/schema_dumper.rb Que no veo que tenga documentación online. Al parecer este SchemaDumper es el que hace el trabajo duro pero no veo donde se le invoca.. Bueno.. cualquier sugerencia es bienvenida Saludos f. -- Fernando Guillén Desarrollador Web Freelance http://www.fernandoguillen.info
on 2009-06-27 00:54
on 2009-06-27 01:20
Fernando Guillen wrote: > ¿En que punto del código de Rails se vuelcan órdenes en schema.rb para > poder hacer yo lo mismo? Ni idea... > Bueno.. cualquier sugerencia es bienvenida Aquà van un par: http://github.com/matthuhiggins/foreigner/tree/master http://github.com/harukizaemon/foreign_key_migrations/tree/master > > Saludos > > f. > Lo propio
on 2009-06-27 01:26
El 27 de junio de 2009 01:18, Jorge Calás Lozano<jcalas@gmail.com> escribió: > http://github.com/matthuhiggins/foreigner/tree/master > http://github.com/harukizaemon/foreign_key_migrations/tree/master Sip Jorge.. yo estuve mirando esta: http://github.com/patientslikeme/migration_helpers/tree/ Pero en ninguno de los casos anteriores veo que modifiquen el schema.rb.. f. -- Fernando Guillén Desarrollador Web Freelance http://www.fernandoguillen.info
on 2009-06-27 01:39
> Que no veo que tenga documentación online. > Al parecer este SchemaDumper es el que hace el trabajo duro pero no > veo donde se le invoca.. Se invoca cuando ejecutas un db:schema:dump
on 2009-06-27 03:50
El 27 de junio de 2009 01:39, alarkspur<alarkspur@gmail.com> escribió: > Que no veo que tenga documentación online. > > Al parecer este SchemaDumper es el que hace el trabajo duro pero no > veo donde se le invoca.. > > Se invoca cuando ejecutas un db:schema:dump Muy bueno.. y además esta task se invoca implÃcitamente cuando invocas a db:migrate http://blog.andrewbeacock.com/2007/07/why-do-rails-migrations-cause-database.html Gracias, aquà tengo una pista. f. -- Fernando Guillén Desarrollador Web Freelance http://www.fernandoguillen.info http://spainrb.org/fernando-guillen
on 2009-06-27 04:33
Pues no estoy encontrando una salida.. por lo menos no una sencilla.
Como bien dice alarkspur ( lo he escrito bien? ) a través de la task
db:schema:dump llegamos a:
ActiveRecord::SchemaDumper.dump()
Y a de aquà a ActiveRecord::SchemaDumper.new.dump() y de aquà a:
SchemaDumper#tables y de aquà a SchemaDumper#indexes:
def indexes(table, stream)
if (indexes = @connection.indexes(table)).any?
add_index_statements = indexes.map do |index|
statment_parts = [ ('add_index ' + index.table.inspect) ]
statment_parts << index.columns.inspect
statment_parts << (':name => ' + index.name.inspect)
statment_parts << ':unique => true' if index.unique
' ' + statment_parts.join(', ')
end
stream.puts add_index_statements.sort.join("\n")
stream.puts
end
end
Los Ãndices normales (no claves foráneas) se imprimen en el schema.rb
con el código de arriba.
Si quiero que se impriman también los de clave foránea deberÃa hacer
un método parecido a éste... pero éste lo tiene fácil porque en el
objeto 'index' tiene todo lo que necesita:
class IndexDefinition < Struct.new(:table, :name, :unique,
:columns) #:nodoc:
end
Pero yo no :/.. se me ocurre que habrÃa que ampliar esta estructura
para almacenar la tabla destino y el campo del Ãndice.. además de un
hueco para diferenciar un tipo de Ãndice de otro.. y luego mirar a ver
cómo se cargan las instancias de esta clase para cargar también mis
datos..
En fÃn.. creo que hay demasiada gente.. el tiro no está claro
Si se os ocurre algo comentarlo a ver
Saludos
f.
--
Fernando Guillén
Desarrollador Web Freelance
http://www.fernandoguillen.info
http://spainrb.org/fernando-guillen
on 2009-06-27 10:42
2009/6/27 Fernando Guillen <fguillen.mail@gmail.com>: > > > objeto 'index' tiene todo lo que necesita: > > Desarrollador Web Freelance > http://www.fernandoguillen.info > http://spainrb.org/fernando-guillen > _______________________________________________ > Ror-es mailing list > Ror-es@lists.simplelogica.net > http://lists.simplelogica.net/mailman/listinfo/ror-es > Parece que has encontrado un punto de Rails que desde luego no está bien diseñado, o al menos no lo mejor diseñado. Lo peor: parece que en la rama 3.0 sigue igual (aunque tiene algo más documentación, gracias a doc-rails). Para mà que vas a tener que hacer cambios significativos en ese SchemaDumper para que funcione lo que quieres. Si buscas por el método indexes lo encontrarás en cada uno de los adaptadores de bases de datos de Rails (uno para MySQL, otro para PostgreSQL y otro para SQLite). Cada uno hace una llamada diferente a la base de datos, y analiza en resultado. Por lo tanto la forma más correcta de abordar el problema serÃa implementar un método "foreign_keys(table_name)" en cada adapter que realizará la llamada correspondiente para cada base de datos (y la implementación por defecto en el abstract adapter devolviera un array vacio, que servirÃa para SQLite, que no almacena las claves foraneas). Esa parte es sencilla. Lo que viene después (que SchemaDumper lea esos resultados y los escriba en el schema.rb) es lo que no le veo solución sencilla. El SchemaDumper tiene un método table, que es el que invoca a indexes. Mi idea serÃa de nuevo implementar un método foreign_keys en el SchemaDumper, y hacer un alias_method_chain (no hay otra forma) de tables, para invocar a ese método cuando se escriba la tabla (hay un problema que es que table imprime sus errores en el schema.rb, pero se los "traga" en Ruby, por lo que puedes llegar a escribir tus foreign keys y que la tabla no haya sido volcada correctamente al schema.rb). Es un poco feo inyectar cosas con alias_method_chain, pero es que creo que no dejan otra. Suerte. PD: ¿Enviaste el correo a las 04.32 de la madrugada? Vaya, desde luego es un problema que no te deja dormir :D
on 2009-06-27 16:01
Hola Daniel, El 27 de junio de 2009 10:41, Daniel Rodriguez Troitiño<notzcoolx@yahoo.es> escribió: > SQLite). Cada uno hace una llamada diferente a la base de datos, y > sencilla. El SchemaDumper tiene un método table, que es el que invoca > a indexes. Mi idea serÃa de nuevo implementar un método foreign_keys > en el SchemaDumper, y hacer un alias_method_chain (no hay otra forma) > de tables, para invocar a ese método cuando se escriba la tabla (hay > un problema que es que table imprime sus errores en el schema.rb, pero > se los "traga" en Ruby, por lo que puedes llegar a escribir tus > foreign keys y que la tabla no haya sido volcada correctamente al > schema.rb). > > Es un poco feo inyectar cosas con alias_method_chain, pero es que creo > que no dejan otra. Sipi.. asà exactamente es como yo lo veo también, pero me parece mucho lÃo, demasiada intromisión para un asunto que querÃa solucionar de manera rápida y no muy estable (ya sabes, sin tests ni cosas serias), meterme en todo este lÃo no me compensa por ahora sobre todo si no existe la posibilidad de recompensa de que estas modificaciones se incluyan algún dÃa en Rails ya que tienen la opinión (acertada, si me preguntan) de no incluir nada en estos módulos que sea tan DB dependiente como es los foreign_keys (no disponibles en sqlite por ejemplo). Al final me decidà por la solución de indicarle a Rails que haga el dump en formato sql: # Use SQL instead of Active Record's schema dumper when creating the test database. # This is necessary if your schema can't be completely dumped by the schema dumper, # like if you have constraints or database-specific column types config.active_record.schema_format = :sql Que según el comentario parece que está hecho para mÃ. Pero tampoco cambia mucho las cosas.. no es que genere un dump en formato sql.. simplemente no genera ninguno: desc "Migrate the database through scripts in db/migrate and update db/schema.rb by invoking db:schema:dump. Target specific version with VERSION=x. Turn off output with VERBOSE=false." task :migrate => :environment do ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true ActiveRecord::Migrator.migrate("db/migrate/", ENV["VERSION"] ? ENV["VERSION"].to_i : nil) Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby end Pero no ganamos nada porque al invocar a db:test:clone se pasa por el forro el 'ActiveRecord::Base.schema_format' y vuelve a usar el dump.ruby para generar la db test: desc "Recreate the test database from the current environment's database schema" task :clone => %w(db:schema:dump db:test:load) Aunque hay una salida: rake db:test:clone_structure Esta sà que hace un volcado en modo sql usando el MysqlAdapter (en mi caso) y lo usa para regenerar la db test.. En fÃn que no veo esto nada claro.. se supone que ActiveRecord::Base.schema_format = :sql está para utilizar sql como sistema de volcado pero simplemente cuando pones cualquier cosa que no sea :ruby lo que hace es no hacer volcado.. en las migraciones aunque sà en otras tasks.. y usando el modo :ruby aunque le indique :sql.. > > Suerte. ;) > > PD: ¿Enviaste el correo a las 04.32 de la madrugada? Vaya, desde luego > es un problema que no te deja dormir :D Más bien era el calor quien no me dejaba dormir, esto simplemente me mantenÃa entretenido :) Gracias Daniel. f. -- Fernando Guillén Desarrollador Web Freelance http://www.fernandoguillen.info http://spainrb.org/fernando-guillen
on 2009-06-28 13:55
No he usado el dump SQL pero en principio la tarea db:test:prepare
cargaria el dump SQL si ActiveRecord::Base.schema_format es :sql.
(Vease databases.rake).
Pero de todos modos no ganarias mucho porque por ejemplo en MySQL se
dice explicitamente:
ActiveRecord::Base.connection.execute('SET foreign_key_checks = 0')
El motivo es que la creacion de tablas y carga/borrado de fixtures no
estan preparados para hacer las cosas en el orden que esas constraints
necesitan.
on 2009-06-28 14:54
El 28 de junio de 2009 13:51, Xavier Noria<fxn@hashref.com> escribió: > No he usado el dump SQL pero en principio la tarea db:test:prepare > cargaria el dump SQL si ActiveRecord::Base.schema_format es :sql. > (Vease databases.rake). No và esto.. Sip.. lo que hace es llamar al db:test:clone_structure que es el que me gustó por que usa sql.. osea que es mejor llamar siempre a db:test:prepare :) Por cierto .. what in the hell is this? Rake::Task[{ :sql => "db:test:clone_structure", :ruby => "db:test:load" }[ActiveRecord::Base.schema_format]].invoke (databases.rake 378) Estos tÃos del core no escribe código hacen balet acrobático. Veo que es lo mismo que: options = { :sql => "db:test:clone_structure", :ruby => "db:test:load" } schema_format = ActiveRecord::Base.schema_format] rake = options[schema_format] Rake::Task[rake].invoke uauu.. que peña :) > > Pero de todos modos no ganarias mucho porque por ejemplo en MySQL se > dice explicitamente: > >  ActiveRecord::Base.connection.execute('SET foreign_key_checks = 0') > > El motivo es que la creacion de tablas y carga/borrado de fixtures no > estan preparados para hacer las cosas en el orden que esas constraints > necesitan. Hombre.. pero luego se vuelven a activar los foreign_key_checks = 1 en alguna parte no?. Está muy bien esa llamada yo lo usaba siempre cuando querÃa cargar un dump.. pero luego las foreign_keys se restablecen y vuelven a estar activas. f. -- Fernando Guillén Desarrollador Web Freelance http://www.fernandoguillen.info http://spainrb.org/fernando-guillen
on 2009-06-28 15:00
2009/6/28 Xavier Noria <fxn@hashref.com>: > estan preparados para hacer las cosas en el orden que esas constraints > necesitan. Por lo que he encontrado eso se llama dentro de un método que se llama disable_referencial_integrity en el adaptador de MySQL (y Postgre). Ese método pone el check a 0, ejecuta el bloque argumento, y vuelve a poner el check al valor que estaba antes. Y po lo que veo luego únicamente se le llamada desde el create_fixtures, por lo que durante los test, si estaba activado (supongo que se podrá configurar MySQL para que el check sea por defecto 1) las comprobaciones de integridad referencial se deberÃan ejecutar. Aunque quizá esté equivocado.
on 2009-06-28 18:06
El 28 de junio de 2009 15:00, Daniel Rodriguez Troitiño<notzcoolx@yahoo.es> escribió: > las comprobaciones de integridad > referencial se deberÃan ejecutar. Claro claro.. son un fuerte atributo de nuestar aplicación, no puede ser que en los tests estén desactivadas y activadas en producción... cosa que ya me pasó cuando en desarrollo tenÃa una sqlite y en producción una mysql.. en producción petaba todo porque la aplicación no estaba preparada para la integridad referencial y aunque los tests pasaban estaban haciendo cosas que no deberÃan :/ f. -- Fernando Guillén Desarrollador Web Freelance http://www.fernandoguillen.info http://spainrb.org/fernando-guillen
on 2009-06-28 18:45
2009/6/28 Daniel Rodriguez Troitiño <notzcoolx@yahoo.es>: > Por lo que he encontrado eso se llama dentro de un método que se llama > disable_referencial_integrity en el adaptador de MySQL (y Postgre). > Ese método pone el check a 0, ejecuta el bloque argumento, y vuelve a > poner el check al valor que estaba antes. Y po lo que veo luego > únicamente se le llamada desde el create_fixtures, por lo que durante > los test, si estaba activado (supongo que se podrá configurar MySQL > para que el check sea por defecto 1) las comprobaciones de integridad > referencial se deberÃan ejecutar. > > Aunque quizá esté equivocado. Ahhh es verdad gracias. No era consciente de que habia cambiado esto, viene de este commit (de 2007, ya hace año y medio): http://github.com/rails/rails/commit/49eafd8c3620bf8e46d21d447fc634a12c8280ab Entonces parece que si generas las constraints en testing las fixtures no serian un problema a dia de hoy.
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.