2013-06-30 27 views
13

Tôi muốn thêm cột được gọi là "payment_type" vào bảng "đơn đặt hàng" của tôi.Thêm cột vào bảng và sửa giá trị cho các bản ghi hiện có trong Rails

Đây là cuộc di cư mà tôi có cho đến nay:

def change 
    add_column :orders, :payment_type, :string 
end 

Tôi muốn payment_type rằng để giữ giá trị "bình thường" cho tất cả các hồ sơ hiện đang trong DB. Tuy nhiên, không phải cho các hồ sơ trong tương lai. Tôi không muốn có giá trị mặc định cho các bản ghi trong tương lai. Tôi có thể làm cái này như thế nào?

Trả lời

30

Như bạn chỉ muốn thiết lập giá trị cho tất cả hồ sơ hiện có, bạn có thể sử dụng update_all, đó là nhanh hơn nhiều so với vòng lặp qua tất cả các trường trật tự, vì nó chỉ sử dụng báo cáo cơ sở dữ liệu và không instanciate tất cả các đơn đặt hàng:

def up 
    add_column :orders, :payment_type, :string 
    Order.reset_column_information 
    Order.update_all(payment_type: 'normal') 
end 

def down 
    remove_column :orders, :payment_type 
end 

update_all không gọi bất kỳ xác thực hoặc trình kích hoạt nào.

+7

Tôi khuyên bạn không nên sử dụng lớp Đặt hàng chính, thay vào đó bạn nên xác định một lớp Đặt hàng sơ khai trong quá trình di chuyển của bạn, nếu không việc di chuyển sẽ ngừng hoạt động trong tương lai nếu lớp Order không còn tồn tại nữa. –

+1

Thậm chí bạn có thể sử dụng phương thức thay đổi thay cho các mehtod. khối ở trên này sẽ thay đổi def thay đổi add_column: đơn đặt hàng,: payment_type,: string Order.reset_column_information Order.update_all (payment_type: 'bình thường') cuối – Amit

+0

xin lỗi, tôi đăng một bình luận sai, 'change' làm việc . –

2
def change 
    add_column :orders, :payment_type, :string 
    Order.all.each do |order| 
    order.update_attributes(:payment_type => 'normal') 
    end 
end 
+0

tốt để biết rằng bạn có thể làm điều này trong 'phương pháp change', và không cần phải viết tách lên xuống phương pháp. – contradictioned

+2

Tôi biết điều này là siêu cũ, nhưng nó không được khuyên dùng ActiveRecord bên trong di chuyển. Mô hình của bạn được cập nhật ngay khi bạn sao chép, nhưng trong quá trình di chuyển, cơ sở dữ liệu của bạn ở trạng thái cũ hơn. Nếu một số thay đổi xảy ra trong tương lai khi Order nhận được default_scope, điều này sẽ không cập nhật tất cả các bản ghi (mặc dù default_scope không có khi di chuyển được tạo). –

0

Nếu bạn muốn dính cột được cập nhật với di cư sau đó trên câu trả lời là tuyệt vời, Nhưng nếu bạn muốn cập nhật cột cục bộ trên máy tính của riêng bạn để khi bạn chia sẻ mã sau đó những người khác không thể nhìn thấy các thuộc tính cập nhật, đơn giản đi để Rails giao diện điều khiển và vòng lặp ...

orders = Order.all 

orders.each do |o| 
    o.update_attribute(:payment_type, 'normal') 
end 

Rails 4

+1

cũng trong bảng điều khiển, sử dụng 'Order.update_all (payment_type: 'normal')' trừ khi bạn cần xác thực (không có khả năng trong trường hợp đơn giản này). Nó nhanh hơn nhiều, xem ở trên, và nó là một lớp lót. –

+0

awww, đủ mát mẻ của nó, Cảm ơn, bỏ phiếu cho câu trả lời ở trên của bạn, nó cũng rực rỡ ... – Awais

1

tôi nghĩ rằng cách dễ nhất để làm điều đó:

class AddStateToSites < ActiveRecord::Migration[5.1] 
     def up 
     add_column :sites, :state, :string, default: :complete # sets default value for existed records 
     change_column :sites, :state, :string, default: nil # changes default value for next 
     end 

     def down 
     remove_column :sites, :state 
     end 
    end 

Và sau đó kiểm tra xem nó trong giao diện điều khiển:

>> Site.last.state 
    Site Load (0.6ms) SELECT "sites".* FROM "sites" ORDER BY "sites"."id" DESC LIMIT $1 [["LIMIT", 1]] 
=> "complete" 
>> Site.new.state 
=> nil 
0

Như những người khác đã đề cập đến nó không phải là thực hành tốt để dựa vào Lớp học có thể sẽ được loại bỏ trong tương lai, vì nó sẽ phanh sự di cư vào thời điểm đó .

Thay vào đó tôi sử dụng để thực hiện liệu mySQL trực tiếp:

execute "UPDATE `orders` SET `payment_type` = 'normal'"