Que o framework Ruby on Rails é uma mão na roda para várias das situações do cotidiano dos desenvolvedores WEB não é segredo. No entanto algumas vez é necessário fazer algumas tarefas que não são tão comuns, como por exemplo conectar nossa aplicação em vários bancos de dados.
Então, vamos lá! Mostrarei a vocês como fazer o ActiveRecord (Classe para abstrair o nível de Banco de Dados) conectar-se a múltiplos banco de dados relacionais (Em um postagem futuro mostrarei como trabalhar com NoSQL), semelhantes, ou diversos dentre SQLite, MySQL, PostgreSQL, OracleSQL, SQL Server ...
Aplicação de Exemplo: Quero cria uma aplicação para gerenciar projetos. No entanto quero que a tabela de usuário fique em uma base da dados externa a aplicação para que outras aplicações futuras também utilizarem essa base de usuários unificada.
Passo 1: Configurar seu database.yml
O primeiro passo, é configurar seu config/database.yml para realizar suas conexões, por exemplo, temos este arquivo:
Este é o padrão de criação com uma base no SQLite, por padrão configuradas com o nome dos ambientes de execução, vamos agora montar uma nova configuração, chamei ela de "database_externa_1" note que faremos conexão com um banco MySQL, o que é perfeitamente possível, já que o árduo trabalho de saber como lidar com cada tipo de base de dados é do ActiveRecord. Lembre também de referenciar as GENs dos adapters que estiver utilizando, neste exemplo "gem 'sqlite3'; gem 'mysql2';"
Passo 2: Criar uma Classe para manipular a conexão
O segundo passo é criar uma classe que servira para manipular a nova conexão, para isso, primeira vamos criar um arquivo chamado "my_databases.rb" dentro da pasta "config/initializers/", tudo que precisamos agora é criar uma classe que herde a classe ActiveRecord::Base, por exemplo:
Muita atenção neste ponto!!! Porque eu criei duas classe?!
Basicamente por organização e simplicidade, para que cada modelo fique explicitamente vinculado a qual conexão ele pertence!
A primeira classe "ProjectdDB" faz referência as conexões padrões (:development, :test, :production) em SQLite. Note no valor que é passado ao método "establish_connection" que é Rails.env.to_sym.
A segunda classe "TestDB" faz referência a nossa base de dados externa em MySQL.
Obs:. "self.abstract_class = true" significa dizer que a classe é abstrata, ou seja, não pode ser instanciada só herdada.
Neste ponto já possuímos toda a nossa aplicação configurada para trabalhar com base de dados distintas. Agora mostrarei através de exemplos como devemos trabalhar.
Exemplo 1: Criar a tabela de usuários.
Como a tabela de usuários deve ficar na base externa devemos tomar alguns procedimentos:
1º - Alterar o arquivo app/models/user.rb
para:
substituir o ActiveRecord::Base por sua subclasse TestDB, assim, a aplicação se onde encontrar a tabela users que será criada.
2º - Radar a migração de forma apropriada
passando a conexão "database_externa_1" como parâmetro, assim, a tabela será criada no banco externo.
Exemplo 2: Criar a tabela de projetos.
Como a tabela de projetos deve ficar na base local:
1º - Alterar o arquivo app/models/project.rb
para:
substituir o ActiveRecord::Base por sua subclasse ProjectDB. Note que toda as relações entre os modelos podem ser construídas normalmente, para a aplicação não faz mais diferença a sua localidade ou tipo. Então configure o modelo "user" também:
2º - Radar a migração de forma apropriada
Veja que não a necessidade de passar a conexão com o parâmetro, pois será utilizada a padrão do ambiente.
Agora, todos os modelos do seu projeto devem herdar de ProjecDB e não mais de ActiveRecord::Base.
Pronto, isso é tudo o que você deve saber para trabalhar com múltiplas base de dados relacionais em seu projeto Ruby on Rails.
Para testar, vá ao terminal:
Imagem de www.askqtp.com |
Aplicação de Exemplo: Quero cria uma aplicação para gerenciar projetos. No entanto quero que a tabela de usuário fique em uma base da dados externa a aplicação para que outras aplicações futuras também utilizarem essa base de usuários unificada.
Passo 1: Configurar seu database.yml
O primeiro passo, é configurar seu config/database.yml para realizar suas conexões, por exemplo, temos este arquivo:
# SQLite version 3.x # gem install sqlite3 # # Ensure the SQLite 3 gem is defined in your Gemfile # gem 'sqlite3' development: adapter: sqlite3 database: db/development.sqlite3 pool: 5 timeout: 5000 # Warning: The database defined as "test" will be erased and # re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: adapter: sqlite3 database: db/test.sqlite3 pool: 5 timeout: 5000 production: adapter: sqlite3 database: db/production.sqlite3 pool: 5 timeout: 5000
Este é o padrão de criação com uma base no SQLite, por padrão configuradas com o nome dos ambientes de execução, vamos agora montar uma nova configuração, chamei ela de "database_externa_1" note que faremos conexão com um banco MySQL, o que é perfeitamente possível, já que o árduo trabalho de saber como lidar com cada tipo de base de dados é do ActiveRecord. Lembre também de referenciar as GENs dos adapters que estiver utilizando, neste exemplo "gem 'sqlite3'; gem 'mysql2';"
development: adapter: sqlite3 database: db/development.sqlite3 pool: 5 timeout: 5000 test: adapter: sqlite3 database: db/test.sqlite3 pool: 5 timeout: 5000 production: adapter: sqlite3 database: db/production.sqlite3 pool: 5 timeout: 5000 database_externa_1: adapter: mysql2 encoding: utf8 database: test_db pool: 5 username: root password: root host: localhost
Passo 2: Criar uma Classe para manipular a conexão
O segundo passo é criar uma classe que servira para manipular a nova conexão, para isso, primeira vamos criar um arquivo chamado "my_databases.rb" dentro da pasta "config/initializers/", tudo que precisamos agora é criar uma classe que herde a classe ActiveRecord::Base, por exemplo:
class ProjectDB < ActiveRecord::Base self.abstract_class = true establish_connection Rails.env.to_sym end class TestDB < ActiveRecord::Base self.abstract_class = true establish_connection :database_externa_1 end
Muita atenção neste ponto!!! Porque eu criei duas classe?!
Basicamente por organização e simplicidade, para que cada modelo fique explicitamente vinculado a qual conexão ele pertence!
A primeira classe "ProjectdDB" faz referência as conexões padrões (:development, :test, :production) em SQLite. Note no valor que é passado ao método "establish_connection" que é Rails.env.to_sym.
A segunda classe "TestDB" faz referência a nossa base de dados externa em MySQL.
Obs:. "self.abstract_class = true" significa dizer que a classe é abstrata, ou seja, não pode ser instanciada só herdada.
Neste ponto já possuímos toda a nossa aplicação configurada para trabalhar com base de dados distintas. Agora mostrarei através de exemplos como devemos trabalhar.
Exemplo 1: Criar a tabela de usuários.
rails generate scaffold user name:string email:string invoke active_record create db/migrate/20121127205353_create_users.rb create app/models/user.rb invoke test_unit create test/unit/user_test.rb create test/fixtures/users.yml invoke resource_route route resources :users invoke scaffold_controller create app/controllers/users_controller.rb invoke erb create app/views/users create app/views/users/index.html.erb create app/views/users/edit.html.erb create app/views/users/show.html.erb create app/views/users/new.html.erb create app/views/users/_form.html.erb invoke test_unit create test/functional/users_controller_test.rb invoke helper create app/helpers/users_helper.rb invoke test_unit create test/unit/helpers/users_helper_test.rb invoke assets invoke coffee create app/assets/javascripts/users.js.coffee invoke scss create app/assets/stylesheets/users.css.scss invoke scss create app/assets/stylesheets/scaffolds.css.scss
Como a tabela de usuários deve ficar na base externa devemos tomar alguns procedimentos:
1º - Alterar o arquivo app/models/user.rb
class User < ActiveRecord::Base attr_accessible :email, :name end
para:
class User < TestDB attr_accessible :email, :name end
substituir o ActiveRecord::Base por sua subclasse TestDB, assim, a aplicação se onde encontrar a tabela users que será criada.
2º - Radar a migração de forma apropriada
rake db:migrate RAILS_ENV=database_externa_1 == CreateUsers: migrating ==================================================== -- create_table(:users) -> 0.0711s == CreateUsers: migrated (0.0712s) ===========================================
passando a conexão "database_externa_1" como parâmetro, assim, a tabela será criada no banco externo.
Exemplo 2: Criar a tabela de projetos.
rails generate scaffold project user_id:integer name:string description:text invoke active_record create db/migrate/20121127212538_create_projects.rb create app/models/project.rb invoke test_unit create test/unit/project_test.rb create test/fixtures/projects.yml invoke resource_route route resources :projects invoke scaffold_controller create app/controllers/projects_controller.rb invoke erb create app/views/projects create app/views/projects/index.html.erb create app/views/projects/edit.html.erb create app/views/projects/show.html.erb create app/views/projects/new.html.erb create app/views/projects/_form.html.erb invoke test_unit create test/functional/projects_controller_test.rb invoke helper create app/helpers/projects_helper.rb invoke test_unit create test/unit/helpers/projects_helper_test.rb invoke assets invoke coffee create app/assets/javascripts/projects.js.coffee invoke scss create app/assets/stylesheets/projects.css.scss invoke scss identical app/assets/stylesheets/scaffolds.css.scss
Como a tabela de projetos deve ficar na base local:
1º - Alterar o arquivo app/models/project.rb
class Project < ActiveRecord::Base attr_accessible :description, :name, :user_id end
para:
class Project < ProjectDB attr_accessible :description, :name, :user_id belongs_to :user end
substituir o ActiveRecord::Base por sua subclasse ProjectDB. Note que toda as relações entre os modelos podem ser construídas normalmente, para a aplicação não faz mais diferença a sua localidade ou tipo. Então configure o modelo "user" também:
class User < TestDB attr_accessible :email, :name has_many :projects end
2º - Radar a migração de forma apropriada
rake db:migrate == CreateUsers: migrating ==================================================== -- create_table(:users) -> 0.0014s == CreateUsers: migrated (0.0015s) =========================================== == CreateProjects: migrating ================================================= -- create_table(:projects) -> 0.0014s == CreateProjects: migrated (0.0015s) ========================================
Veja que não a necessidade de passar a conexão com o parâmetro, pois será utilizada a padrão do ambiente.
Agora, todos os modelos do seu projeto devem herdar de ProjecDB e não mais de ActiveRecord::Base.
Pronto, isso é tudo o que você deve saber para trabalhar com múltiplas base de dados relacionais em seu projeto Ruby on Rails.
Para testar, vá ao terminal:
rails c Loading development environment (Rails 3.2.8) 1.9.3p194 :001 > User.create(:name => "AJ Alves", :email => "aj.alves@zerokol.com") (0.1ms) BEGIN SQL (0.3ms) INSERT INTO `users` (`created_at`, `email`, `name`, `updated_at`) VALUES ('2012-11-27 21:37:28', 'aj.alves@zerokol.com', 'AJ Alves', '2012-11-27 21:37:28') (36.6ms) COMMIT => #<user 21:37:28="21:37:28" 2="2" aj.alves="aj.alves" alves="alves" created_at:="created_at:" email:="email:" id:="id:" name:="name:" updated_at:="updated_at:" zerokol.com="zerokol.com"> 1.9.3p194 :002 > Project.create(:user_id => 1, :name => "Teste", :description => "Um projeto de teste") (0.0ms) begin transaction SQL (0.4ms) INSERT INTO "projects" ("created_at", "description", "name", "updated_at", "user_id") VALUES (?, ?, ?, ?, ?) [["created_at", Tue, 27 Nov 2012 21:38:16 UTC +00:00], ["description", "Um projeto de teste"], ["name", "Teste"], ["updated_at", Tue, 27 Nov 2012 21:38:16 UTC +00:00], ["user_id", 1]] (117.6ms) commit transaction => #<project 1="1" 21:38:16="21:38:16" 2="2" created_at:="created_at:" de="de" description:="description:" este="este" id:="id:" m="m" name:="name:" projeto="projeto" teste="teste" updated_at:="updated_at:" user_id:="user_id:"> 1.9.3p194 :003 > u = User.first User Load (0.4ms) SELECT `users`.* FROM `users` LIMIT 1 => #<user 1="1" 21:33:42="21:33:42" aj.zerokol="aj.zerokol" alves="alves" created_at:="created_at:" email:="email:" gmail.com="gmail.com" id:="id:" name:="name:" updated_at:="updated_at:"> 1.9.3p194 :004 > u.projects Project Load (0.2ms) SELECT "projects".* FROM "projects" WHERE "projects"."user_id" = 1 => [#<project 1="1" 21:33:58="21:33:58" created_at:="created_at:" d="d" description:="description:" dsfsdf="dsfsdf" este="este" id:="id:" name:="name:" sdf="sdf" sdfs="sdfs" updated_at:="updated_at:" user_id:="user_id:">, #<project 1="1" 21:38:16="21:38:16" 2="2" created_at:="created_at:" de="de" description:="description:" este="este" id:="id:" m="m" name:="name:" projeto="projeto" teste="teste" updated_at:="updated_at:" user_id:="user_id:">] 1.9.3p194 :005 > p = Project.first Project Load (0.2ms) SELECT "projects".* FROM "projects" LIMIT 1 => #<project 1="1" 21:33:58="21:33:58" created_at:="created_at:" d="d" description:="description:" dsfsdf="dsfsdf" este="este" id:="id:" name:="name:" sdf="sdf" sdfs="sdfs" updated_at:="updated_at:" user_id:="user_id:"> 1.9.3p194 :006 > p.user User Load (0.4ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1 => #<user 1="1" 21:33:42="21:33:42" aj.zerokol="aj.zerokol" alves="alves" created_at:="created_at:" email:="email:" gmail.com="gmail.com" id:="id:" name:="name:" updated_at:="updated_at:"> 1.9.3p194 :007 >
Conexão com múltiplas DBs no Ruby On Rails
Reviewed by AJ Alves
on
terça-feira, novembro 27, 2012
Rating:
Nenhum comentário:
Postar um comentário