Di chuyển đường ray cho cột thay đổi


327

Chúng tôi có script/generate migration add_fieldname_to_tablename fieldname:datatypecú pháp để thêm các cột mới vào một mô hình.

Trên cùng một dòng, chúng ta có tập lệnh / tạo để thay đổi kiểu dữ liệu của một cột không? Hay tôi nên viết SQL trực tiếp vào quá trình di chuyển vanilla của mình?

Tôi muốn thay đổi một cột từ datetimeđến date.

Câu trả lời:


547

Tôi nghĩ rằng điều này sẽ làm việc.

change_column :table_name, :column_name, :date

13
@b_ayan: theo như tôi biết, các từ ma thuật duy nhất trong tên di chuyển là "thêm" và "xóa".
Alex Korban

1
Sắp xếp các đường ray ở đây, nhưng tôi hiểu câu trả lời nhưng không nhận xét về câu trả lời này. Làm rõ đánh giá cao :)
Alan H.

7
Khi bạn tạo một di chuyển, bạn đặt tên cho nó (ví dụ: add_fieldname_to_tablename trong câu hỏi trên). Nếu nó bắt đầu bằng "thêm" hoặc "xóa" thì việc di chuyển sẽ được tự động điền mã để thêm hoặc xóa các cột, giúp bạn tự viết mã đó.
Alex Korban

5
Cũng đáng ghi nhớ, bạn nên thay thế changehành động thông thường bằng hành động updownhành động riêng biệt , như change_columnlà một sự di chuyển không thể đảo ngược và sẽ gây ra lỗi nếu bạn cần quay lại.
DaveStephens

1
@QPaysTaxes lên nên chứa những gì bạn muốn thay đổi cột của bạn từ và sang, và xuống nên chứa cách đảo ngược sự thay đổi đó.
DaveStephens

98

Bạn cũng có thể sử dụng một khối nếu bạn có nhiều cột để thay đổi trong một bảng.

Thí dụ:

change_table :table_name do |t|
  t.change :column_name, :column_type, {options}
end

Xem tài liệu API trên lớp Bảng để biết thêm chi tiết.


88

Tôi không biết nếu bạn có thể tạo một di chuyển từ dòng lệnh để thực hiện tất cả điều này, nhưng bạn có thể tạo một di chuyển mới, sau đó chỉnh sửa di chuyển để thực hiện việc này.

Nếu tablename là tên của bảng của bạn, tên trường là tên của trường của bạn và bạn muốn thay đổi từ datetime thành ngày, bạn có thể viết một di chuyển để làm điều này.

Bạn có thể tạo một di chuyển mới với:

rails g migration change_data_type_for_fieldname

Sau đó chỉnh sửa di chuyển để sử dụng change_table:

class ChangeDataTypeForFieldname < ActiveRecord::Migration
  def self.up
    change_table :tablename do |t|
      t.change :fieldname, :date
    end
  end
  def self.down
    change_table :tablename do |t|
      t.change :fieldname, :datetime
    end
  end
end

Sau đó chạy di chuyển:

rake db:migrate

32

Như tôi đã tìm thấy trong các câu trả lời trước đó, cần ba bước để thay đổi loại cột:

Bước 1:

Tạo tệp di chuyển mới bằng mã này:

rails g migration sample_name_change_column_type

Bước 2:

Chuyển đến /db/migratethư mục và chỉnh sửa tệp di chuyển bạn đã thực hiện. Có hai giải pháp khác nhau.

  1. def change
        change_column(:table_name, :column_name, :new_type)
    end

2.

    def up
        change_column :table_name, :column_name, :new_type
    end

    def down
        change_column :table_name, :column_name, :old_type
    end

Bước 3:

Đừng quên thực hiện lệnh này:

rake db:migrate

Tôi đã thử nghiệm giải pháp này cho Rails 4 và nó hoạt động tốt.


1
Ở bước 2, lần đầu tiên sẽ thất bại sau khi chạy rake db: rollback, tôi khuyên bạn nên kiểm tra lần thứ hai
Feuda

Có một quy ước đường ray cho phép mọi thứ được thực hiện ít nhiều khi tạo tệp di chuyển mà không cần đến nó, sau đó chỉnh sửa nó?
BKSpurgeon

@BKSpurgeon Có, kiểm tra tài liệu ở đây: edgeguides.rubyonrails.org/active_record_migations.html
Aboozar Rajabi

12

Với đường ray 5

Từ hướng dẫn Rails :

Nếu bạn muốn di chuyển thực hiện điều gì đó mà Active Record không biết cách đảo ngược, bạn có thể sử dụng reversible:

class ChangeTablenameFieldname < ActiveRecord::Migration[5.1]
  def change
    reversible do |dir|
      change_table :tablename do |t|
        dir.up   { t.change :fieldname, :date }
        dir.down { t.change :fieldname, :datetime }
      end
    end
  end
end

8

Chỉ cần tạo di chuyển:

rails g migration change_column_to_new_from_table_name

Cập nhật di chuyển như thế này:

class ClassName < ActiveRecord::Migration
  change_table :table_name do |table|
    table.change :column_name, :data_type
  end
end

và cuối cùng

rake db:migrate

2

Một cách khác để thay đổi kiểu dữ liệu bằng cách sử dụng di chuyển

Bước 1: Bạn cần xóa tên trường loại dữ liệu bị lỗi bằng cách di chuyển

Ví dụ:

rails g migration RemoveFieldNameFromTableName field_name:data_type

Ở đây đừng quên chỉ định loại dữ liệu cho lĩnh vực của bạn

Bước 2: Bây giờ bạn có thể thêm trường với kiểu dữ liệu chính xác

Ví dụ:

rails g migration AddFieldNameToTableName field_name:data_type

Thế là xong, bây giờ bảng của bạn sẽ được thêm vào với trường loại dữ liệu chính xác, mã hóa ruby ​​hạnh phúc !!


1

Đây là tất cả giả định rằng kiểu dữ liệu của cột có một chuyển đổi ngầm định cho bất kỳ dữ liệu hiện có. Tôi đã gặp phải một số tình huống trong đó dữ liệu hiện có, giả sử Stringcó thể được chuyển đổi hoàn toàn thành kiểu dữ liệu mới, giả sử Date.

Trong tình huống này, thật hữu ích khi biết bạn có thể tạo chuyển đổi với chuyển đổi dữ liệu. Cá nhân, tôi thích đặt chúng trong tệp mô hình của mình và sau đó xóa chúng sau khi tất cả các lược đồ cơ sở dữ liệu đã được di chuyển và ổn định.

/app/models/table.rb
  ...
  def string_to_date
    update(new_date_field: date_field.to_date)
  end

  def date_to_string
    update(old_date_field: date_field.to_s)
  end
  ...
    def up
        # Add column to store converted data
        add_column :table_name, :new_date_field, :date
        # Update the all resources
        Table.all.each(&:string_to_date)
        # Remove old column
        remove_column :table_name, :date_field
        # Rename new column
        rename_column :table_name, :new_date_field, :date_field
    end

    # Reversed steps does allow for migration rollback
    def down
        add_column :table_name, :old_date_field, :string
        Table.all.each(&:date_to_string)
        remove_column :table_name, :date_field
        rename_column :table_name, :old_date_field, :date_field
    end

0

Để hoàn thành câu trả lời trong trường hợp chỉnh sửa giá trị mặc định :

Trong bảng điều khiển đường ray của bạn:

rails g migration MigrationName

Trong quá trình di chuyển:

  def change
    change_column :tables, :field_name, :field_type, default: value
  end

Sẽ giống như:

  def change
    change_column :members, :approved, :boolean, default: true
  end
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.