De vez em quando, somos tentados a usar modelos em migrações de trilhos. Essa ideia engenhosa, no entanto, acaba sendo uma armadilha, pois o ciclo de vida do código (modelo, neste caso) não corresponde necessariamente ao das migrações. Um exemplo é dado pelo Rails Guide mostrando como criar um modelo local dentro da migração para evitar tais conflitos.
Outro exemplo seria renomear um nome de modelo (por exemplo, de class Item < ActiveRecord::Base
para class Product < ActiveRecord::Base
) e sua tabela correspondente. Isso interromperia todas as migrações anteriores que utilizavam esse modelo. Por exemplo, a migração seguinte seria interrompida:
class SomeMigration < ActiveRecord::Migration
method def
items = Item.all
...
end
end
Note que neste ponto a tabela items
já existe (desde a nova migração, que muda de nome tem naturalmente um timestamp maior e deve ser executada após esta migração) e usando SQL puro (ou respectivo DB DSL) usando execute
(como alguns podem propor) pode evitar que todas essas migrações sejam interrompidas:
class SomeMigration < ActiveRecord::Migration
method def
execute << -SQL
...
SELECT "items".* FROM "items"
...
SQL
end
end
Isso, no entanto, cria um novo problema:
- Mudar para outro banco de dados (por exemplo, MySQL para PostgreSQL) exige a reescrita de todas as migrações, incluindo esses códigos. Em outras palavras, o sistema não é mais agnóstico de DB
- A conveniente Active Record Query Interface (por exemplo
ActiveRecord.find
) não pode mais ser usada.
A melhor solução (que encontrei até agora) é criar um modelo genérico na migração e fazer com que ele acesse uma tabela específica:
class SomeMigration < ActiveRecord::Migration
class GenericModel < ActiveRecord::Base
self.table_name = 'items'
end
method def
GenericModel.find ...
...
end
end
Dessa forma, podemos conservar o recurso agnóstico de DB do RoR e aproveitar a rica interface de consulta sem temer modificações futuras no modelo.
Isenção de responsabilidade: esta solução é uma versão modificada de “Como usar modelos em suas migrações (sem matar gatinhos)”