12/08/2018, 16:56

Tìm hiểu về Migration

Migration là một tính năng của Active record cho phép bạn thay đổi cả cấu trúc và dữ liệu trong database. Thay vì thay đổi trực tiếp vào database thì Rails cho phép bạn sử dụng Ruby DSL để mô tả việc thay đổi các table. Tiện gần đây dự án mình gặp vấn đề về migration nên mình viết bài viết này. Bài ...

Migration là một tính năng của Active record cho phép bạn thay đổi cả cấu trúc và dữ liệu trong database. Thay vì thay đổi trực tiếp vào database thì Rails cho phép bạn sử dụng Ruby DSL để mô tả việc thay đổi các table. Tiện gần đây dự án mình gặp vấn đề về migration nên mình viết bài viết này. Bài toán đặt ra là Khách hàng muốn rollback migration về thời điểm nào đó chỉ để chạy code ở version nào đó thôi mà không phải code hiện tại. Và lúc đó bên mình đã rollback nhưng bị lỗi rollback mà trong lúc code k ai nghĩ đến trường hợp đó cả. Đó cũng là một vấn đề mà ta cần hiểu rõ hơn về migration để tránh những trường hợp như vậy. Sau khi đọc bài viết bạn có thể biết thêm về:

  • Hiểu về migration, các cách tạo
  • Các cách chạy migration, rollback chúng
  • Hiểu thêm về schema

1. Tổng quan

Migration là một cách thuận tiện để thay đổi cấu trúc bảng và dữ liệu trong database 1 cách dễ dàng. Bằng cách sử dụng Ruby DSL bạn k cần phải viết SQL bằng tay, nó có thể giúp bạn thay đổi database 1 cách độc lập Tưởng tượng mỗi migration tương ứng vs 1 version của database. Ban đầu, schema là rỗng, và mỗi lần migration thì sẽ modify để add hoặc remove table, columns hoặc rows. Active record biết cách để update schema theo thời gian. Và từ bất cứ thời điểm nào trong quá khứ cũng có thể update version của schema đến bản mới nhất. Active record cũng sẽ update file db/schema.rb để làm cho thống nhất với cấu trúc mới nhất của database. Chúng ta cùng nhìn qua ví dụ về 1 migration:

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

Đây là 1 migration tạo bảng products trong database. Có 2 trường đó là name và description. Một cột khóa chính là id cũng sẽ được thêm vào sau khi chạy migration này, đây là khóa chính mặc định cho tất cả model của Active Record. timestamps sẽ thêm vào bảng 2 cột đó là : created_at và updated_at. Các cột này sẽ được quản lý tự động bởi ActiveRecord nếu chúng tồn tại Trước khi thực hiện migration thì không tồn tại table nào cả. Run migration thì table sẽ được sinh ra. Và Active record cũng có cách để back lại cái migration lúc nãy bằng cách là Rollback lại cái migration đó thì bảng được tạo lúc trước sẽ bị xóa. Ta cũng có thể viết migration theo cách khác để hiểu cách nó rollback:

class ChangeProductsPrice < ActiveRecord::Migration[5.0]
  def change
    reversible do |dir|
      change_table :products do |t|
        dir.up   { t.change :price, :string }
        dir.down { t.change :price, :integer }
      end
    end
  end
end

dir.up là chạy migration. dir.down là chạy rollback lại, quay lại thời điểm trước khi chạy migration Ví dụ như nếu chúng ta change_column thì rollback sẽ bị lỗi, buộc phải viết code theo kiểu này.

2. Tạo migration

2.1 Tạo migration

Migration được lưu tại thành các file tại db/migrate. Tên của các file migration sẽ theo dạng YYYYMMDDHHMMSS_create_products.rb . File name kèm theo thời gian để phân biệt các version migration. Ví dụ: file name là 20080906120000_create_products.rb thì class CreateProducts phải được định nghĩa. Rails sử dụng dấu thời gian này để xác định migration nào cần được chạy và theo thứ tự nào, do đó, nếu bạn đang sao chép migration từ một ứng dụng khác hoặc tự tạo ra một tệp tin, hãy nhận biết vị trí của nó theo thứ tự. Và tất nhiên, cứ mỗi lần tạo migration chúng ta k thể ngồi tính thời gian để tạo file dc. Active Record cung cấp một cách tạo đơn giản, dễ dàng:

$ bin/rails generate migration AddPartNumberToProducts

Cau lệnh sẽ tạo ra 1 migration mới:

class AddPartNumberToProducts < ActiveRecord::Migration[5.0]
  def change
  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[5.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[5.0]
  def change
    create_table :products do |t|
      t.string :name
      t.string :part_number
    end
  end
end

2.2 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[5.0]
  def change
    create_table :products do |t|
      t.string :name
      t.text :description
 
      t.timestamps
    end
  end
end

Bạn có thể thêm nhiều cột khác nếu muốn             </div>
            
            <div class=

0