Desenvolver uma aplicação não significa apenas implementar novas funções ou corrigi-la. Por vezes, é necessário reverter as alterações e voltar à fase anterior de um projeto. Um problema frequente que pode surgir quando se trabalha em vários ramos está relacionado com a manutenção da versão adequada de uma estrutura de base de dados. Os programadores que utilizam rails têm à sua disposição soluções prontas a utilizar. Estas soluções suportam a implementação e o controlo das alterações à base de dados - são as migrações. Não vou descrever como funciona e quais as possibilidades que oferece - gostaria de me concentrar no problema de manter a versão adequada de uma estrutura de base de dados ao mudar de ramo.
A camada de base de dados de uma aplicação é um ser separado e é controlada apenas por migrações. Ao criar novas migrações, lembre-se de tornar reversível a transformação planeada de uma estrutura de base de dados. Claro que, em casos extremos, podemos criar IrreversívelMigração no para baixo método. Isto também informará nós sobre o facto de a migração não poder ser revertida. Existem diferentes tipos de alterações que efectuamos na migração - criação, modificação e remoção de tabelas, colunas ou índices. As operações de eliminação e modificação são as mais sensíveis às alterações. Porquê? Consideremos o seguinte cenário: Estamos a trabalhar com a ramificação principal, que é o nosso principal caminho de trabalho. Atualmente, temos uma tabela:
class CreateArticles < ActiveRecord::Migration
def change
criar_tabela :artigos do |t|
t.string :nome
t.text :descrição
t.string :status, null: false
t.timestamps null: false
end
end
end
O nosso Artigo O modelo tem validações que exigem a presença de nome, descrição e estatuto atributos.
class Article < ActiveRecord::Base
valida :nome, presença: true
valida :descrição, presença: true
valida :status, presença: true
fim
Estamos a implementar mudanças na nossa artigos mesa em caraterística e eliminamos o ramo de desenvolvimento estatuto coluna.
class RemoveStatusColumnFromArticles < ActiveRecord::Migration
def change
remove_column :articles, :status, :string
end
fim
Executamos a migração:
$ [example/feature]: bundle exec rake db:migrate
== 20150605120955 RemoveStatusColumnFromArticles: migrando ===================
-- remove_column(:articles, :status, :string)
-> 0.0717s
== 20150605120955 RemoveStatusColumnFromArticles: migrado (0.0718s) ==========
O esquema de uma base de dados é alterado:
diff --git a/db/schema.rb b/db/schema.rb
index 2a100a9..76438c1 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,14 +11,13 @@ #
Recomenda-se vivamente que verifique este ficheiro no seu sistema de controlo de versões.
-ActiveRecord::Schema.define(version: 20150605120350) do
+ActiveRecord::Schema.define(version: 20150605120955) do
createtable "artigos", force: :cascade do |t|
t.string "nome"
t.text "description" (descrição)
- t.string "status", null: false t.datetime "createdat", null: false
t.datetime "updated_at", null: false
final
end
De seguida, submetemos as alterações ao ficheiro caraterística branch. Para simular este problema, mudamos o ramo atual para master. A estrutura base foi alterada pela migração, que exclui o ramo estatuto coluna no caraterística ramo. Vamos tentar utilizar o seguinte comando:
Article.create!(name: "Kaboom", description: "Lorem ipsum...", status: "active")
O que é que acontece depois de executar as acções acima mencionadas? código? O erro: ActiveRecord::UnknownAttributeError: atributo desconhecido 'status' para o artigo será levantado e isso deve-se à versão incompatível da estrutura de uma base de dados. Antes de mudar o ramo para master, devemos reverter a migração que exclui o estatuto da coluna Artigo mesa.
O que podemos fazer para verificar se temos de reverter algumas migrações antes de mudar os ramos? Com a utilização do sistema de controlo de versões (aqui é git) podemos verificar o nosso trabalho criando um alias útil:
~/.gitconfig
[alias]
migrations = "!f() { git diff --name-only $1..$2 db/migrate | tr -d '[A-Za-z/_.]'; }; f"
Executando o git migrations caraterística principal resultará na lista de versões de migração, que estão localizadas em caraterística e que não podem ser encontrados em mestre.
$ [example/feature]: recurso mestre do git migrations
20150605120955
Graças a esta informação, podemos facilmente reverter as alterações efectuadas na estrutura da base de dados antes de mudar para a base principal.
$ [example/feature]: bundle exec rake db:migrate:down VERSION=20150605120955
== 20150605120955 RemoveStatusColumnFromArticles: reverting ===================
-- add_column(:articles, :status, :string)
-> 0.0009s
== 20150605120955 RemoveStatusColumnFromArticles: revertido (0.0045s) ==========
Outra coisa que devemos fazer depois de reverter a migração é restaurar o estado de um esquema de base de dados.
$ [example/feature]: git status
Recurso no ramo
Alterações não preparadas para confirmação:
(use "git add ..." para atualizar o que será submetido)
(use "git checkout -- ..." para descartar as alterações no diretório de trabalho)
modificado: db/schema.rb
nenhuma alteração adicionada ao commit (use "git add" e/ou "git commit -a")
$ [exemplo/caraterística]: git checkout db/schema.rb
$ [exemplo/caraterística]: git status
Recurso no ramo
nada para submeter, diretório de trabalho limpo
Agora podemos mudar facilmente para o mestre ramo.
O exemplo dado não é um problema complicado de resolver, mas deve ajudá-lo a perceber como é importante manter a estrutura de uma base de dados durante a mudança no contexto de trabalho.