Setting up multiple databases in Rails: the definitive guide



  • Có nhiều lý do khác nhau khiến bạn có thể cân nhắc việc có nhiều cơ sở dữ liệu trong ứng dụng Ruby on Rails. Trong trường hợp cụ thể của tôi, tôi cần phải lưu trữ số lượng lớn dữ liệu đại diện cho hành vi của người dùng: nhấp chuột, các trang truy cập, những thay đổi lịch sử, v.v ...
    Tôi đã đọc nhiều giải pháp khác nhau, tuy nhiên tôi không thể tìm thấy một trong đó có thể có đầy đủ bao gồm làm thế nào để:

    • Có file migrate và schema riêng biệt cho mỗi cơ sở dữ liệu.
    • Dùng Rails generate để tạo các file migration riêng biệt cho mỗi cơ sở dữ liệu.
    • Cung cấp các rake task cho từng cơ sở dữ liệu cụ thể (Ví dụ rake db:migrate cho từng cơ sở dữ liệu khác nhau).
    • Tích hợp RSpec.
    • Làm việc với Database Cleaner.
    • Làm việc trên Heroku.

    Create the custom database files

    Trong bài hướng dẫn này, chúng ta sẽ thiết lập cơ sở dữ liệu thứ hai có tên là Stats. Để làm được như vậy, chúng ta sẽ bắt trước cách Rails xử lý với cơ sở dữ liệu chính.
    Đầu tiên, ta tạo một file config/database_stats.yml là file cấu hình kết nối đến cơ sở dữ liệu Stats (nó có chức năng giống như config/database.yml mà chúng ta thường dùng cho cơ sở dữ liệu chính). Nội dung của file này như sau:

    development:
      adapter: postgresql
      encoding: utf8
      host: localhost
      pool: 10
      database: myapp_stats_development
      username: postgres
      password:
    
    test:
      adapter: postgresql
      encoding: utf8
      host: localhost
      pool: 10
      database: myapp_stats_test
      username: postgres
      password:
    
    production:
      adapter: postgresql
      encoding: utf8
      url:  <%= ENV["DATABASE_STATS_URL"] %>
      pool: <%= ENV["DB_POOL"] || 5 %>
    

    Lưu ý rằng chúng ta đã đặt tên cụ thể cho các cơ sở dữ liệu, thực hiện theo các đúng quy ước đặt tên của Rails.

    Tiếp đến, chúng ta sẽ tạo một thư mục để lưu trữ tất cả các file migration và file schema của cơ sở dữ liệu Stats. Về cơ bản sao chép lại thư mục db của dự án Rails. Tạo thư mục db_stats trong thư Rails root và đảm bảo cấu trúc và các tệp tin giống với thư mục db . Bạn sẽ có một cái gì đó như sau

    -- db
       |-- migrate
       schema.rb
       seeds.rb
    -- db_stats
       |-- migrate
       schema.rb
       seeds.rb
    

    Các file schema.rbseeds.rb, cùng với thư mục migrate chỉ tạo ra và để trống.

    Add Rake tasks

    Để xử lý và điều khiển được cơ sở dữ liệu Stats, cho phép create , migrate, drop v.v..., chúng ta sẽ cần tạo ra Rake task. Chúng ta sẽ tạo ra các hàm giống với các hàm mà Rails cung cấp đối với cơ sở dữ liệu chính.

    Tạo file lib/tasks/db_stats.rake có nội dung như sau:

    task spec: ["stats:db:test:prepare"]
    
    namespace :stats do
    
      namespace :db do |ns|
    
        task :drop do
          Rake::Task["db:drop"].invoke
        end
    
        task :create do
          Rake::Task["db:create"].invoke
        end
    
        task :setup do
          Rake::Task["db:setup"].invoke
        end
    
        task :migrate do
          Rake::Task["db:migrate"].invoke
        end
    
        task :rollback do
          Rake::Task["db:rollback"].invoke
        end
    
        task :seed do
          Rake::Task["db:seed"].invoke
        end
    
        task :version do
          Rake::Task["db:version"].invoke
        end
    
        namespace :schema do
          task :load do
            Rake::Task["db:schema:load"].invoke
          end
    
          task :dump do
            Rake::Task["db:schema:dump"].invoke
          end
        end
    
        namespace :test do
          task :prepare do
            Rake::Task["db:test:prepare"].invoke
          end
        end
    
        # append and prepend proper tasks to all the tasks defined here above
        ns.tasks.each do |task|
          task.enhance ["stats:set_custom_config"] do
            Rake::Task["stats:revert_to_original_config"].invoke
          end
        end
      end
    
      task :set_custom_config do
        # save current vars
        @original_config = {
          env_schema: ENV['SCHEMA'],
          config: Rails.application.config.dup
        }
    
        # set config variables for custom database
        ENV['SCHEMA'] = "db_stats/schema.rb"
        Rails.application.config.paths['db'] = ["db_stats"]
        Rails.application.config.paths['db/migrate'] = ["db_stats/migrate"]
        Rails.application.config.paths['db/seeds'] = ["db_stats/seeds.rb"]
        Rails.application.config.paths['config/database'] = ["config/database_stats.yml"]
      end
    
      task :revert_to_original_config do
        # reset config variables to original values
        ENV['SCHEMA'] = @original_config[:env_schema]
        Rails.application.config = @original_config[:config]
      end
    end
    

    Trong đoạn code trên, ta tạo tất cả các task có tên giống với các task mà Rails cung cấp (migrate, setup, v.v...) với namspace là stats:db. Chúng ta chạy vòng lặp qua tất cả các task của namspace db và đảm bảo rằng task stats:set_custom_config luôn chạy trước các task khác, còn task stats:revert_to_original_config luôn chạy sau khi mỗi task đã kết thúc

    # append and prepend proper tasks to all tasks defined in stats:db namespace
    ns.tasks.each do |task|
      task.enhance ["stats:set_custom_config"] do
        Rake::Task["stats:revert_to_original_config"].invoke
      end
    end
    

    Chúng ta phải làm điều này vì, không may, Rails hỗ trợ cho nhiều cơ sở dữ liệu không phải là tuyệt đối, vì thế chúng ta cần cung cấp các thủ thuật nhỏ để làm cho mọi thứ hoạt động. Vì lý do này, chúng ta phải đặt các biến môi trường và biến cấu hình cụ thể cho các giá trị tùy chỉnh phù hợp với cơ sở dữ liệu Stats của chúng ta trước khi chúng ta chạy các task và sau đó đảm bảo rằng các giá trị ban đầu được thiết lập lại khi các task đó đã được chạy. Hai task sau giúp làm điều đó:

    task :set_custom_config do
      # save current vars
      @original_config = {
        env_schema: ENV['SCHEMA'],
        config: Rails.application.config.dup
      }
     
      # set config variables for custom database
      ENV['SCHEMA'] = "db_stats/schema.rb"
      Rails.application.config.paths['db'] = ["db_stats"]
      Rails.application.config.paths['db/migrate'] = ["db_stats/migrate"]
      Rails.application.config.paths['db/seeds'] = ["db_stats/seeds.rb"]
      Rails.application.config.paths['config/database'] = ["config/database_stats.yml"]
    end
     
    task :revert_to_original_config do
      # reset config variables to original values
      ENV['SCHEMA'] = @original_config[:env_schema]
      Rails.application.config = @original_config[:config]
    end
    

    Cuối cùng, nếu bạn đang sử dụng RSpec, bạn có thể thêm một task spec, để đảm bảo rằng cơ sở dữ liệu Stats được tự động chuẩn bị khi chạy test:

    task spec: ["stats:db:test:prepare"]
    

    Việc cài đặt đã hoàn thành, bây giờ chúng ta có thể tạo và migrate cơ sở dữ liệu Stats như sau:

    $ rake stats:db:create
    $ rake stats:db:migrate
    

    Add a custom generator

    Thật không may chúng ta không thể sử dụng ActiveRecord::Generators::MigrationGenerator bởi vì nó đã được fix cứng code trong thư mục db.migrate/ như bên dưới:

    def create_migration_file
      set_local_assigns!
      validate_file_name!
      migration_template @migration_template, "db/migrate/#{file_name}.rb"
    end
    

    Do đó, chúng ta cần tạo một generator riêng cho cơ sở dữ liệu Stats. Tạo generator trong file lib/generators/stats_migration_generator.rb như sau

    require 'rails/generators/active_record/migration/migration_generator'
     
    class StatsMigrationGenerator < ActiveRecord::Generators::MigrationGenerator
      source_root File.join(File.dirname(ActiveRecord::Generators::MigrationGenerator.instance_method(:create_migration_file).source_location.first), "templates")
     
      def create_migration_file
        set_local_assigns!
        validate_file_name!
        migration_template @migration_template, "db_stats/migrate/#{file_name}.rb"
      end
    end
    

    Cách sử dụng generator này rất đơn giản như sau:

    $ rails g stats_migration create_clicks create  db_stats/migrate/20151201191642_create_clicks.rb
    

    Sau đó ta chay rake stats:db:migrate để tạo bảng cho cơ sở dữ liệu Stats

    Finalize connection and models

    Tạo file config/initializers/db_stats.rb có nội dung như sau để đọc các cấu hình kết nối đến Stats:

    # save stats database settings in global var
    DB_STATS = YAML::load(ERB.new(File.read(Rails.root.join("config","database_stats.yml"))).result)[Rails.env]
    

    Sau đó trong mỗi model của cơ sở dữ liệu Stats, ta thêm đoạn sau để kết nối đến Stats. Ví dụ

    class Click < ActiveRecord::Base
      establish_connection DB_STATS
    
    end
    

    Kết luận

    Như vậy, trong bài viết trên đây, đã trình bày cách cài đặt để một ứng dụng Rails có thể sử dụng nhiều cơ sở dữ liệu. Hy vọng nó sẽ giúp ích cho mọi người. Cảm ơn đã đọc bài viết.

    Tài liệu tham khảo

    http://www.ostinelli.net/setting-multiple-databases-rails-definitive-guide/
    Nguồn: Viblo


Hãy đăng nhập để trả lời
 

Có vẻ như bạn đã mất kết nối tới LaptrinhX, vui lòng đợi một lúc để chúng tôi thử kết nối lại.