Postado originalmente em codecrate.com
As migrações do Rails foram originalmente projetadas para manipular esquemas de banco de dados . Adicionar tabelas, colunas e índices são todos os casos de uso que são incrivelmente bem suportados e até mesmo oferecem suporte a recursos mais avançados, como retornar ao estado anterior do esquema. Manipular dados de produção também é uma ocorrência comum para desenvolvedores, mas como fazer isso no Rails?
Importar dados de arquivos simples, atualizar registros e limpar registros em um estado incorreto são eventos regulares. Muitos desenvolvedores lidariam com essas tarefas abrindo o console Rails em um servidor de produção e executando manualmente alguns comandos para cuidar dos negócios. Você pode realizar todas essas tarefas usando migrações Rails, o que é significativamente menos arriscado do que dar a cada desenvolvedor acesso direto ao seu banco de dados para executar scripts únicos ao vivo em seus dados de produção . O uso de migrações também fornece acesso fácil a revisões de código de branch de recursos e até mesmo a testes de unidade .
Aqui estão alguns protocolos que eu recomendo ao criar suas migrações de dados Rails:
Registrar todas as coisas
Muitas migrações de esquema têm um caminho claro para a reversão se algo der errado, mas as migrações de dados são muito mais difíceis de reverter. É absolutamente essencial para suas migrações fornecer o máximo de informações de depuração possível para se / quando algo der errado.
Aqui está um exemplo simples que destaca o uso do say_with_time
auxiliar para auditar quanto tempo levou uma etapa de migração e quantos registros foram afetados. Certifique-se de retornar o número de linhas afetadas dentro do bloco !
def UpdateInvalidUsers < ActiveRecord::Migration
def up
say_with_time "Updating invalid users..." do
count = 0
User.find_each do |user|
say "Updating user: #{user.id}"
user.update!(status: 'valid')
count += 1
end
count
end
end
end
Estado de auditoria pré e pós-execução
O registro durante a execução de uma migração é bastante simples e também é muito útil registrar informações antes da execução sobre o estado atual do sistema. Por exemplo, registrar o número de registros inválidos antes do início da migração é um grande ponto de dados.
Uma boa migração de dados também deve assegurar que a operação foi concluída com êxito e gerar um erro se algo não for concluído conforme o esperado.
Tomando nosso exemplo anterior, aqui está uma versão expandida que adiciona um registro simples de pré e pós-execução, além de asserções.
def UpdateInvalidUsers < ActiveRecord::Migration
def up
say "Found #{User.where(status: 'invalid').count} invalid records"
say_with_time "Updating invalid users..." do
count = 0
User.find_each do |user|
say "Updating user: #{user.id}"
user.update!(status: 'valid')
count += 1
end
count
end
invalid_count = User.where(status: 'invalid').count
fail "Found #{invalid_count} invalid records" unless invalid_count == 0
end
end
Reexecutável por padrão
Se uma migração de dados gerar um erro, o que você deve fazer? As migrações de dados devem ser projetadas para serem reexecutáveis e se ocorrer algum erro, o Rails irá reexecutar automaticamente sua migração na próxima vez que você executar .rake db:migrate
Também é uma boa ideia definir classes internas em sua migração que sombreiam seus modelos de aplicativo e usam reset_column_information
para garantir que sua migração tenha acesso à versão mais recente do esquema do modelo .
Vamos dar uma última olhada neste exemplo e ter certeza de que a migração pode ser executada novamente e não atualiza os registros que já foram corrigidos.
def UpdateInvalidUsers < ActiveRecord::Migration
def up
say "Found #{User.where(status: 'invalid').count} invalid records"
say_with_time "Updating invalid users..." do
count = 0
User.where(status: 'invalid').find_each do |user|
say "Updating user: #{user.id}"
user.update!(status: 'valid')
count += 1
end
count
end
invalid_count = User.where(status: 'invalid').count
fail "Found #{invalid_count} invalid records" unless invalid_count == 0
end
end
Com essas técnicas fundamentais em seu currículo, você pode levar suas migrações de dados para o próximo nível e até mesmo explorar ferramentas adicionais como a gem migration_data que torna as migrações Rails ainda mais fáceis.