quinta-feira, 8 de novembro de 2012

Múltiplos Bancos de Dados com Rails

O Rails segue o conceito de convention over configuration que assume diversos padrões em vários aspectos das aplicações até que se defina o contrário. Por exemplo, o Rails assume que a aplicação será RESTful, ou seja, utilizará os métodos do protocolo HTTP para identificar os tipos de ações a serem executadas para cada requisição do cliente. Também assume que a aplicação será dividida em camadas seguindo o padrão MVC. E uma das convenções assume que você terá um banco de dados, com três ambientes: desenvolvimento, testes e produção.

O princípio de convention over configuration tem sido utilizado pela grande maioria de frameworks modernos, com o intuito de tornar o desenvolvimento mais ágil, pois o desenvolver tem pouquíssima coisa, ou quase nada, para configurar na sua aplicação recém criada, exceto se houver uma situação muito específica que necessita de uma configuração especial. E sendo um framework maduro, o Rails abre espaço para praticamente qualquer configuração que seja necessária.

E uma das situações especiais que podemos ter em uma aplicação é a utilização de mais de um banco de dados. Um dos exemplo mais comuns seria ter uma base de um sistema legado e a base do sistema novo, mas poderia ser também um sistema que utiliza um banco de dados relacional e outro não relacional, ou uma base de dados transacionais e outra base analítica (um data warehouse), ou outra situação mais específica ainda.

Neste post, vou exemplificar a utilização de um banco de dados principal em conjunto com um banco legado, que foge à convenção do Rails, mas que é totalmente possível e simples de ser implementado.

Primeiro Passo: database.yml


Por padrão, ao ser criada com rails new, a aplicação guarda as informações de conexão de banco de dados no arquivo database.yml sob o diretório config. Neste já constará uma configuração padrão para os três ambientes (desenvolvimento, testes e produção). Não vou detalhar estas configurações porque foge ao objetivo do post, mas para adicionar um novo banco de dados nos três ambientes será necessário criar novas configurações neste arquivo, diferenciando os bancos de algum forma, conforme o exemplo abaixo:


   ...
   ...
   ...
   legado_development:
     ...
     ...

   legado_test:
     ...
     ...

   legado_production:
     ...
     ...


É importante observar que essas novas configurações precisam apontar para um banco de dados pronto, pois o recurso de migrations do Rails não atende atualmente a múltiplos bancos de dados.

Segundo Passo: Criar manualmente os modelos



Então podemos criar manualmente um modelo sob a estrutura de diretórios padrão do Rails (app/models) e utilizar o método establish_connection para apontar para o banco de dados legado. Não utilizamos o gerador (rails generate model...) porque o Rails automaticamente criaria as migrations para os comandos DDL que criariam a respectiva tabela no banco de dados.

class Pessoa < ActiveRecord::Base
  establish_connection "legado_#{RAILS_ENV}"
  ...
  ...
end


A partir desse ponto, tudo já deve estar funcional, porém podemos melhorar. Provavelmente teremos várias tabelas neste banco de dados legado e será inconveniente chamar o comando establish_connection em diversos modelos, por isso é interessante explorar a herança de classes para centralizar esta configuração. Assim teremos uma classe genérica abstrata que herda de ActiveRecord::Base e que configura o banco de dados, e os nossos modelos herdam dessa classe em vez de herdar diretamente de ActiveRecord::Base. Ficaria assim:

class BaseLegado < ActiveRecord::Base
  self.abstract_class = true
  establish_connection "legado_#{RAILS_ENV}"
  ...
  ...
end

class Cliente < BaseLegado
  ...
  ...
end

class Produto < BaseLegado
  ...
  ...
end


Conclusão



As convenções do Rails simplificam muita coisa, tornam o desenvolvimento realmente ágil e mesmo quando é necessário configurar manualmente alguma coisa o framework também torna essa tarefa simples.

Na conexão com outro banco de dados, é possível que haja divergências com as convenções de nomenclatura do Rails, por exemplo, o Rails sempre pluraliza o nome das tabelas, de forma que o modelo Cliente vai buscar uma tabela chamada clientes. Outro problema é se precisarmos fazer referência entre modelos que são de bancos de dados diferentes. Para essas e outras situações recomendo as bibliografias que utilizei como base para este post: Rails Recipes, recipe 3 e 10, e o capítulo 4 de Advanced Rails.

Até a próxima!

Nenhum comentário:

Postar um comentário