Migration là gì? Tổng hợp thông tin chi tiết về migration

Migration là một chức năng quan trọng trong Active Record, giúp người phát triển thay đổi cấu trúc và dữ liệu trong cơ sở dữ liệu một cách linh hoạt. Thay vì thực hiện các thay đổi trực tiếp trên cơ sở dữ liệu, Rails cung cấp khả năng sử dụng ngôn ngữ mô tả Ruby DSL để định nghĩa và mô tả những sự thay đổi cần thực hiện trên các bảng.

Migration là gì?

Migrations là cách thuận tiện để thay đổi cấu trúc cơ sở dữ liệu theo thời gian một cách nhất quán. Chúng sử dụng một DSL Ruby để bạn không cần phải viết SQL bằng tay, cho phép cấu trúc và các thay đổi của bạn độc lập với cơ sở dữ liệu. Bạn có thể coi mỗi migration như một ‘phiên bản’ mới của cơ sở dữ liệu. Một schema bắt đầu với không có gì trong đó, và mỗi migration sẽ sửa đổi nó để thêm hoặc xóa bảng, cột hoặc các mục. Active Record biết cách cập nhật schema của bạn theo dõi thời gian, đưa nó từ bất kỳ điểm nào trong lịch sử đến phiên bản mới nhất. Active Record cũng sẽ cập nhật tệp db/schema.rb của bạn để phản ánh cấu trúc cơ sở dữ liệu được cập nhật.

Dưới đây là ví dụ về một migration:

class CreateProducts < ActiveRecord::Migration[6.0]
  def change
    create_table :products do |t|
      t.string :name
      t.text :description

      t.timestamps
    end
  end
end

Ví dụ trên là một migration để tạo bảng “products” trong cơ sở dữ liệu. Bảng này bao gồm hai trường là “name” và “description”. Một cột khóa chính “id” cũng sẽ được thêm vào sau khi migration được chạy; đây là khóa chính mặc định cho tất cả các mô hình của Active Record. Hai cột “created_at” và “updated_at” sẽ được tự động thêm vào bảng thông qua timestamps khi migration được thực hiện. Các cột này sẽ được quản lý tự động bởi Active Record nếu chúng tồn tại.

Trước khi migration được chạy, không có bảng nào tồn tại. Sau khi chạy migration, bảng “products” sẽ được tạo ra. Active Record cung cấp cách để rollback một migration bằng cách sử dụng lệnh Rollback. Khi một migration được rollback, bảng tạo ra từ migration đó sẽ bị xóa.

Để hiểu cách rollback hoạt động, có thể viết migration theo một cách khác để mô tả quá trình rollback.

class RemoveDescriptionFromProducts < ActiveRecord::Migration[6.0]
  def change
    remove_column :products, :description, :text
  end
end

Với ví dụ trên, việc rollback migration sẽ xóa cột “description” từ bảng “products”.

Tạo migration

Tạo migration

Các migration được lưu trữ dưới dạng các tệp tin trong thư mục db/migrate. Tên của các tệp tin migration được đặt theo định dạng YYYYMMDDHHMMSS_create_products.rb. Thời gian được tích hợp vào tên tệp để phân biệt giữa các phiên bản migration khác nhau. Ví dụ, nếu tên tệp là 20080906120000_create_products.rb, thì lớp CreateProducts phải được định nghĩa trong đó.

Rails sử dụng thời gian này để xác định migration nào cần phải chạy và theo thứ tự nào. Do đó, khi bạn sao chép migration từ một ứng dụng khác hoặc tạo nó thủ công, quan trọng để duy trì thứ tự của chúng. Tuy nhiên, để giảm bớt công đoạn tính toán thời gian khi tạo tệp tin mới mỗi lần migration, Active Record cung cấp một cách đơn giản và tiện lợi như:

$ bin/rails generate migration AddPartNumberToProducts

Câu lệnh sẽ tạo ra một migration mới:

class AddPartNumberToProducts < ActiveRecord::Migration[6.0]
  def change
    add_column :products, :part_number, :string
  end
end

Nếu migration tên có dạng “AddXXXToYYY” hoặc “RemoveXXXFromYYY” sẽ tạo ra các migration add_column hoặc remove_column. Ta có thể thêm vào các column và type của chúng theo sau:

$ bin/rails generate migration AddPartNumberToProducts part_number:string

Sẽ tạo ra:

class AddPartNumberToProducts < ActiveRecord::Migration[6.0]
  def change
    add_column :products, :part_number, :string
  end
end

Các migration có tên theo dạng CreateXXX và theo sau là danh sách các tên column và type của chúng sẽ tạo ra table có tên XXX với những column đã liệt kê. Ví dụ:

$ bin/rails generate migration CreateProducts name:string part_number:string

Sẽ tạo ra migration:

class CreateProducts < ActiveRecord::Migration[6.0]
  def change
    create_table :products do |t|
      t.string :name
      t.string :part_number

      t.timestamps
    end
  end
end

Tạo model

Khi tạo model có thể tạo migration theo đó. Ví dụ chúng ta tạo 1 model mới tên là Product.

$ bin/rails generate model Product name:string description:text

Nó sẽ tạo ra 1 migration mới như sau:

class CreateProducts < ActiveRecord::Migration[6.0]
  def change
    create_table :products do |t|
      t.string :name
      t.text :description

      t.timestamps
    end
  end
end

Chạy migration

Rails cung cấp một tập hợp các lệnh trong bin/rails tasks để quản lý quá trình chạy migration. Trong số đó, lệnh phổ biến nhất là rails db:migrate. Khi thực hiện lệnh này, chỉ các migration chưa được chạy sẽ được thực hiện. Các migration đã chạy trước đó sẽ không được thực hiện lại, và chúng sẽ tuân theo thứ tự thời gian của chúng.

Lưu ý rằng khi chạy db:migrate, Rails cũng tự động thực hiện lệnh db:schema:dump để cập nhật file db/schema.rb, đảm bảo rằng nó phản ánh đúng cấu trúc của cơ sở dữ liệu. Điều này giúp đồng bộ hóa schema của bạn với cơ sở dữ liệu hiện tại.

Nếu bạn muốn chạy một migration cụ thể, bạn có thể sử dụng lệnh rails db:migrate với việc chỉ định version của migration. Điều này được thực hiện bằng cách sử dụng số phiên bản dài từ tên tệp migration và chạy lệnh tương ứng.

$ bin/rails db:migrate VERSION=20080906120000

Nếu version của migration, chẳng hạn như 20080906120000, lớn hơn phiên bản hiện tại, quá trình chạy migration sẽ thực hiện tất cả các thay đổi (phương thức up) của các migration, kể cả migration có phiên bản 20080906120000, và không thực hiện bất kỳ migration nào có phiên bản lớn hơn sau đó.

Rolling back

Rollback được sử dụng khi chúng ta phát hiện lỗi trong quá trình tạo migration và muốn điều chỉnh lại chúng, quay lại trạng thái trước khi chạy migration lỗi. Để thực hiện rollback, chúng ta có thể sử dụng lệnh:

$ bin/rails db:rollback

Lệnh này sẽ thực hiện rollback đến thời điểm mới nhất của migration. Nếu muốn rollback nhiều version trước đó, có thể chỉ định tham số STEP. Ví dụ:

$ bin/rails db:rollback STEP=3

Lệnh trên sẽ rollback 3 migration gần nhất. Chúng ta cũng có thể sử dụng lệnh db:migrate:redo để rollback và chạy lại migration:

$ bin/rails db:migrate:redo STEP=3

Các lệnh này giúp chúng ta sửa lỗi trong các migration mà không cần phải thực hiện reset toàn bộ quá trình migration.

Lưu ý rằng khi tạo migration, chúng ta nên kiểm tra xem nó có thể rollback được hay không. Điều này có thể phụ thuộc vào các yếu tố như sử dụng change_column (không thể rollback), hoặc khi thêm điều kiện vào để chạy migration.

Cài đặt database

Ta dùng db:setup sẽ giúp tạo ra database và load schema và khởi tạo chúng với seed.

Reset database

Dùng db:reset để drop database và cài đặt lại nó. Nó tương đương với 2 câu lệnh: db:dropdb:setup.

Chạy 1 migration bất kì

Nếu bạn muốn chạy 1 migration với up hoặc down, ta có thể dùng db:migrate:updb:migrate:down. Và thêm version đằng sau để xác định đó là file migration nào

$ bin/rails db:migrate:up VERSION=20080906120000

sẽ chạy 20080906120000 với những thay đổi (up method). Nó cũng kiểm tra xem migration này đã chạy chưa và sẽ không làm gì hết nếu Active Record xác định nó đã được chạy.

Chạy migration trên các môi trường khác nhau

Mặc định, khi chạy lệnh db:migrate, quá trình sẽ diễn ra trong môi trường development. Tuy nhiên, nếu bạn muốn thực hiện migration trên các môi trường khác, chỉ cần thêm biến môi trường sau lệnh là RAILS_ENV. Ví dụ, nếu bạn muốn chạy migration trên môi trường test, sử dụng lệnh sau:

$ bin/rails db:migrate RAILS_ENV=test

Schema

File schema giúp bạn có cái nhìn tổng quan về các thuộc tính của đối tượng Active Record. Những thông tin này không được xuất hiện trực tiếp trong mã nguồn của model, mà thay vào đó, chúng được tạo ra thông qua các migration.

Có hai phương pháp để Dump schema. Cách thức Dump được cấu hình trong file config/application.rb, thông qua config.active_record.schema_format. Bạn có thể chỉ định giá trị là sql hoặc :ruby.

Nếu bạn chỉ định :ruby, schema sẽ được lưu tại db/schema.rb. Mở file này sẽ cung cấp một cái nhìn giống như một bảng migration lớn, cho phép bạn kiểm tra và hiểu rõ cấu trúc của cơ sở dữ liệu mà không cần xem qua mã nguồn của model.

Migrations và Seed Data

Mục đích chính của tính năng migration trong Rails là phát ra các lệnh để sửa đổi cấu trúc sử dụng một quy trình nhất quán. Migrations cũng có thể được sử dụng để thêm hoặc sửa đổi dữ liệu. Điều này hữu ích trong một cơ sở dữ liệu hiện tại không thể bị hủy bỏ và tạo lại, như là một cơ sở dữ liệu sản xuất.

Để thêm dữ liệu ban đầu sau khi tạo cơ sở dữ liệu, Rails có một tính năng tích hợp gọi là ‘seeds’ giúp tăng tốc quá trình này. Điều này đặc biệt hữu ích khi thường xuyên tải lại cơ sở dữ liệu trong môi trường phát triển và kiểm thử, hoặc khi thiết lập dữ liệu ban đầu cho sản xuất.

Để bắt đầu sử dụng tính năng này, mở tệp db/seeds.rb và thêm một số mã Ruby, sau đó chạy lệnh bin/rails db:seed. Mã ở đây nên là idempotent để có thể thực hiện bất cứ lúc nào trong mọi môi trường.

Vậy là bạn đã tìm hiểu chi tiết về migration là gì. Hy vọng bài viết đã cung cấp đến bạn những kiến thức bổ ích và cần thiết. Đừng quên theo dõi Megaweb thường xuyên để cập nhật thêm nhiều thông tin khác nhé!

FEATURED TOPIC