Config multiple databases in Rails
Khi dự án của bạn yêu cầu xây dựng database cho một ứng dụng cho phép chia sẻ một vài dữ liệu chung cho một vài sites khác. Ví dụ như là chúng ta có 2 ứng dụng là notes và memories cần dùng chung database là bảng user để khi mà người dùng có tài khoản trong notes thì đều có thể đăng nhập vào ...
Khi dự án của bạn yêu cầu xây dựng database cho một ứng dụng cho phép chia sẻ một vài dữ liệu chung cho một vài sites khác. Ví dụ như là chúng ta có 2 ứng dụng là notes và memories cần dùng chung database là bảng user để khi mà người dùng có tài khoản trong notes thì đều có thể đăng nhập vào memories thông qua tài khoản đó trong khi đó chúng ta cũng có những database riêng để lưu trữ dữ liệu cho những phần khác của những sites đó. Vậy chúng ta cần phải làm gì?
Đến đây chắc bạn cũng sẽ nghĩ cần phải tách dữ liệu và lưu trữ vào những database riêng biệt, qua đó có thể include vào những sites khác nhau để dùng. Vậy làm sao để có thể sử dụng multiple database trong ứng dụng, dưới đây mình sẽ hướng dẫn config và migration multiple databases trong Rails application. Bài hướng dẫn sử dụng Rails 4.x
Đầu tiên để ứng dụng có thể hoạt động ta cần configure database connection và mọi việc này hoàn toàn có thể nằm trong 1 file duy nhất là database.yml. Có rất nhiều cách khác nhau để config các database, ở đây mình sẽ giới thiệu cách mà mình thấy là rõ ràng và có thể biểu hiện được multi database ở đây. Chúng ta có 2 database là db1 và db2 sẽ config như sau:
# config/database.yml defaults: &defaults adapter: mysql2 encoding: utf8 pool: 5 username: root password: collation: utf8_unicode_ci socket: /var/run/mysqld/mysqld.sock db1: development: database: db1_development <<: *defaults test: database: db1_test <<: *defaults production: database: db1_production <<: *defaults db2: development: database: db2_development <<: *defaults test: database: db2_test host: localhost <<: *defaults production: database: db2_production host: localhost <<: *defaults development: database: db1_development <<: *defaults test: database: db1_development <<: *defaults
Lưu ý, nhìn bên trên kia bạn vẫn thấy có config development đúng không? Đừng bận tâm nhiều đến nó, vì đó chỉ là một khai báo mặc định app sẽ nhận nó, còn lại chúng ta sẽ sử dụng những config trong db1 và db2 để tiến hành migration và connect để sử dụng.
Tiếp đó chúng ta sẽ định nghĩa constants cho config của db1 và db2 để có thể dễ dàng sử dụng ở tất cả mọi nơi cần dùng (migration và model), ta có thể định nghĩa chúng trong application.rb
# config/application.rb module MultiMysql db_conf = YAML.load_file("config/database.yml") DB1_CONF = db_conf["db1"][Rails.env] DB2_CONF = db_conf["db2"][Rails.env] .... end
Tiếp đến chúng ta sẽ xử lý phần migration. Đầu tiên, bạn tạo các file migration như bình thường, có thể sử dụng lệnh rails g model ... của rails sẽ tạo ra file migration như bình thường, sau đó bạn sẽ thêm vào mỗi file @connection để biết được là mình đang connect đến database nào, muốn cho bảng đó nằm trong database nào thì ta connect đến database đó. Hay để dễ quản lý, mình sẽ chia migration ra làm 2 folder riêng biệt, 1 lưu trữ migration file cho database 1 được đặt tên là db1 và cái còn lại sẽ lưu trữ migration file cho database 2 với tên là db2. Sau đó mình sẽ tạo file base cho mỗi db1 và db2 trong đó có chứa connection kết nối tới Mysql của db1 và db2. Ví dụ file migration của db1
# db/migrate/db1/db1_migration_base.rb class Db1MigrationBase < ActiveRecord::Migration protected def change @connection = ActiveRecord::Base.establish_connection(MultiMysql::DB1_CONF).connection end end
# db/migrate/db1/20160505121212_create_users.rb require_relative './db1_migration_base' class CreateUsers < Db1MigrationBase def change super create_table :users do |t| t.string :name t.string :email t.timestamps null: false end end end
Giờ, nếu muốn thêm bảng nào vào db1 bạn cũng chỉ cần tạo file migration như bình thường sau đó chuyển file đó vào thư mục db1 và cho nó kế thừa từ Db1MigrationBase sử dụng super function change để có connection đến config db1 và sử dụng như bình thường.
Một điều lưu ý là bạn cần tạo database bằng tay, không như database bình thường là chúng ta chỉ cần dùng lệnh rake db:create vì nó sẽ chỉ tạo database config trong development. Giờ bạn có thể dùng lệnh rake db:migrate như bình thường. Sau khi migration xong ta có thể kiểm tra database trong mysql, thu được kết quả như sau:
Cuối cùng, ta sẽ nói cho model biết connect đến database nào bằng cách sử dụng establish_connection của ActiveRecord.
# app/models/user.rb class User < ActiveRecord::Base establish_connection MultiMysql::DB1_CONF has_many :products end
# app/models/product.rb class Product < ActiveRecord::Base establish_connection MultiMysql::DB2_CONF belongs_to :user end
Chúng ta hoàn toàn có thể sử dụng association bình thường.
User.first.products User Load (0.4ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1 Product Load (0.6ms) SELECT `products`.* FROM `products` WHERE `products`.`user_id` = 1
Vậy là xong, bây giờ bạn có thể config bao nhiêu database tùy ý.
Reference
Ruby on Rails Connect to Multiple Databases and Migrations Multiple-Databases In Single Rails Application Connecting Models To Different Databases In Rails
Demo
https://github.com/nguyenngoc2505/multi-database-demo