23

Tôi đã có di chuyển add_column chạy tốt. Tuy nhiên, sau khi chạy nó và bắn lên một giao diện điều khiển, tôi sẽ tìm thấy các cột first_name và last_name hoàn toàn trống rỗng. Tôi đã thử sử dụng save! thay vào đó và nó có cùng tác dụng - không có lỗi nào được báo cáo. Dưới đây là bản gốc:Rails 3.1: không thể ghi vào cột trong cùng một di chuyển thêm nó

class UserAddFirstNameAndLastName < ActiveRecord::Migration 
    def change 
    # add column first name, last name string 
    add_column :users, :first_name, :string 
    add_column :users, :last_name, :string 

    User.all.each do |u| 
     u.first_name = 'first name' 
     u.last_name = 'last name' 
     u.save 
    end 
    end 
end 

Tôi cũng nghĩ rằng đây có thể là một số vấn đề cấp tải, vì vậy tôi chèn dòng User để buộc các lớp người sử dụng để tải lại trước khi vòng lặp. Không có con xúc xắc.

Khi tôi chia thành hai lần di chuyển, hiệu quả mong muốn đã đạt được. Có ai có một lời giải thích cho điều này? Tôi thề tôi thậm chí đã làm điều này trong cùng một dự án với quá khứ di cư.

Ghi chú khác: Thiết lập cho công cụ người dùng, thêm các cột mới vào attr_accessible trong lớp Người dùng trước khi chạy di chuyển.

+1

mu là quá ngắn có một câu trả lời tuyệt vời để giải thích những gì đang xảy ra và phải làm gì nhưng tôi cũng khuyên bạn nên chia hai thành các di chuyển khác nhau. Tạo cột trong một, điền vào một cột khác. Điều này ngăn chặn sự cố bạn đang gặp phải và khiến cho việc khôi phục ít xảy ra lỗi hơn. –

Trả lời

37

Bạn đang tải lớp Người dùng ở đâu đó trước khi quá trình di chuyển của bạn chạy như vậy User hơi nhầm lẫn về cấu trúc của riêng nó. Giải pháp là gọi reset_column_information sau khi thêm cột của bạn:

Đặt lại tất cả thông tin được lưu trong bộ nhớ cache, sẽ khiến chúng được tải lại theo yêu cầu tiếp theo.

Các mô hình sử dụng phổ biến nhất cho phương pháp này có lẽ là trong một sự chuyển đổi, khi chỉ sau khi tạo một bảng bạn muốn để cư nó với một số giá trị mặc định

Phần Using Models in Your Migrations của Migrations Guide có thể là đáng xem cũng.

Cố gắng lăn trở lại và sử dụng một di cư như thế này:

def change 
    # add column first name, last name string 
    add_column :users, :first_name, :string 
    add_column :users, :last_name, :string 

    User.reset_column_information 

    User.all.each do |u| 
    u.first_name = 'first name' 
    u.last_name = 'last name' 
    u.save 
    end 
end 

Tôi đã kiểm tra này với ba di cư như thế này:

# 1: Don't touch Model before the new columns. 
def change 
    add_column :models, :some_column, :string 
    Model.all.each { |m| m.some_column = 'pancakes'; m.save } 
end 

# 2: Pull in Model before adding the new columns. 
def change 
    puts Model.all.count 
    add_column :models, :some_column, :string 
    Model.all.each { |m| m.some_column = 'pancakes'; m.save } 
end 

# 3: Pull in Model before adding the new columns but use reset_column_information 
def change 
    puts Model.all.count 
    add_column :models, :some_column, :string 
    Model.reset_column_information 
    Model.all.each { |m| m.some_column = 'pancakes'; m.save } 
end 

Người đầu tiên làm việc tốt, điều thứ hai cho biết thêm some_column nhưng lá nó với giá trị NULL, thứ ba cũng hoạt động.

Tôi đoán rằng một cái gì đó trong khởi tạo ứng dụng của bạn (có thể từ Devise) đang khiến người dùng và giản đồ của nó được tải, sau đó bạn thêm một cột. Nhưng, rõ ràng, Người dùng chỉ biết một phần về cột mới khi cuộc gọi u.first_name hoạt động nhưng một cái gì đó được lưu trữ bên trong Người dùng để ngăn không cho thuộc tính được ghi vào cơ sở dữ liệu.

+0

Xác nhận rằng đây là vấn đề với một báo trước. Tôi chỉ sử dụng ví dụ đầu tiên và thứ ba của bạn cùng nhau trong một lần di chuyển. Người đầu tiên không lưu vào cơ sở dữ liệu. Tôi grep'd thư mục DB của chúng tôi và tôi đã đúng về trước - Tôi có di cư cũ với tiết kiệm như thế này. Một cái gì đó chúng tôi đã thêm vào dự án của chúng tôi là gây ra các mô hình để tải trước trước khi di chuyển ... Tôi nghi ngờ nó có thể là đá quý 'active_reload'. Chúng tôi chưa nâng cấp lên Rails 3.2 nhưng tôi nhận thấy đây là tính năng tiêu chuẩn hiện nay. Tôi hy vọng sẽ xác nhận/bác bỏ điều này với thử nghiệm nếu tôi có thời gian. –

+0

@Eric: Nội dung nào đó trong quá trình khởi tạo của bạn đang tải trước lớp mô hình của bạn. (1) làm việc cho tôi bởi vì không có gì trong khởi tạo của tôi là tải trước bất cứ điều gì; 'đặt Model.all.count' in (2) và (3) chỉ là một cách dễ dàng để mô phỏng quá trình tải trước đang diễn ra trong môi trường của bạn. 'active_reload' có vẻ giống như một kẻ tình nghi. Thêm 'reset_column_information' nếu bạn thay đổi và sử dụng mô hình trong một lần di chuyển có lẽ là một thói quen tốt để tham gia. –

+0

Điều này không hoạt động trong Rails 4. –

Các vấn đề liên quan