7

Tôi đang viết di chuyển để thêm cột vào bảng. Giá trị của cột phụ thuộc vào giá trị của hai cột hiện có khác. Cách tốt nhất/nhanh nhất để làm điều này là gì? Hiện tại tôi có điều này nhưng không chắc chắn nếu đó là cách tốt nhất vì bảng nhóm có thể rất lớn.thêm cột cơ sở dữ liệu với di chuyển Rails và điền nó vào một cột khác

class AddColorToGroup < ActiveRecord::Migration 
    def self.up 
    add_column :groups, :color, :string 
    Groups = Group.all.each do |g| 
     c = "red" if g.is_active && is_live 
     c = "green" if g.is_active 
     c = "orange" 
     g.update_attribute(:type, c) 
    end 
    end 

    def self.down 

    end 
end 
+0

Tại sao điều ngược lại không thể làm? – Robert

+0

đó chỉ là lỗi đánh máy tôi đã thực hiện khi chỉnh sửa ở đây;) – user1404536

Trả lời

1

tôi sẽ làm điều này trong một

after_create 
# or 
after_save 

trong mô hình ActiveRecord của bạn:

hoặc trong di cư có lẽ bạn sẽ phải làm một số SQL như thế này:

execute('update groups set color = <another column>') 

Đây là một ví dụ trong Hướng dẫn đường ray:

http://guides.rubyonrails.org/migrations.html#using-the-up-down-methods

+2

cảm ơn, nhưng cột phải được điền trước cho tất cả các nhóm hiện có. Điều này sẽ chỉ hoạt động cho các nhóm mới được tạo. – user1404536

2

Tôi đặc biệt khuyên bạn nên thực hiện tổng số ba truy vấn thay thế. Luôn tận dụng cơ sở dữ liệu so với vòng lặp qua một loạt các mục trong một mảng. Tôi nghĩ một cái gì đó như thế này có thể làm việc.

Vì mục đích viết này, tôi giả sử is_active sẽ kiểm tra trường đang hoạt động khi 1 đang hoạt động. Tôi sẽ giả định sống là như nhau là tốt.

Rails 3 cách tiếp cận

class AddColorToGroup < ActiveRecord::Migration 
    def self.up 
    add_column :groups, :color, :string 
    Group.where(active: 1, live: 1).update_all(type: "red") 
    Group.where(active: 1, live: 0).update_all(type: "green") 
    Group.where(active: 0, live: 0).update_all(type: "orange") 
    end 
end 

Hãy xem lại những tài liệu hướng dẫn của update_all here.

Rails 2.x cách tiếp cận

class AddColorToGroup < ActiveRecord::Migration 
    def self.up 
    add_column :groups, :color, :string 
    Group.update_all("type = red", "active = 1 AND live = 1") 
    Group.update_all("type = red", "active = 1 AND live = 0") 
    Group.update_all("type = red", "active = 0 AND live = 0") 
    end 
end 

Rails 2 documentation

+0

: (ứng dụng của tôi không sử dụng Rails 3. Cảm ơn bạn! – user1404536

+0

Trả lời cập nhật để bao gồm Rails phiên bản 2.x của phản hồi – Robert

+0

Điều này có giải quyết được vấn đề của bạn không? – Robert

12

Nó thường là một ý tưởng tồi để tham khảo mô hình của bạn từ sự di cư của bạn như thế này. Vấn đề là các di chuyển chạy theo thứ tự và thay đổi trạng thái cơ sở dữ liệu khi chúng đi, nhưng các mô hình của bạn không được phiên bản. Không có gì đảm bảo rằng mô hình như nó tồn tại khi di chuyển được viết sẽ vẫn tương thích với mã di chuyển trong tương lai. Ví dụ: nếu bạn thay đổi hành vi của các thuộc tính is_active hoặc is_live trong tương lai thì việc di chuyển này có thể bị hỏng. Di chuyển cũ hơn này sẽ chạy đầu tiên, chống lại mã mô hình mới và có thể không thành công. Trong ví dụ cơ bản của bạn ở đây, nó có thể không cắt, nhưng điều này đã đốt cháy tôi trong triển khai trước khi các trường được thêm vào và xác nhận không thể chạy (tôi biết mã của bạn bỏ qua các xác nhận hợp lệ, nhưng nói chung đây là một mối quan tâm).

Giải pháp yêu thích của tôi cho điều này là thực hiện tất cả việc di chuyển loại này bằng SQL thuần túy. Có vẻ như bạn đã cân nhắc điều đó, vì vậy tôi sẽ giả sử bạn đã biết phải làm gì ở đó.

Một tùy chọn khác, nếu bạn có một số logic kinh doanh lông hoặc chỉ muốn mã để xem thêm Railsy, ​​bao gồm phiên bản cơ bản của mô hình vì nó tồn tại khi di chuyển được viết trong tệp di chuyển.Ví dụ: bạn có thể đặt lớp này trong tệp di chuyển:

class Group < ActiveRecord::Base 
end 

Trong trường hợp của bạn, có thể điều đó đủ để đảm bảo rằng mô hình sẽ không bị hỏng. Giả sử activelive là các trường boolean trong bảng tại thời điểm này (và do đó sẽ bất cứ khi nào di chuyển này được chạy trong tương lai), bạn sẽ không cần thêm bất kỳ mã nào nữa. Nếu bạn có logic kinh doanh phức tạp hơn, bạn có thể đưa nó vào phiên bản mô hình di chuyển cụ thể này.

Bạn thậm chí có thể cân nhắc sao chép toàn bộ các phương thức từ mô hình của mình sang phiên bản di chuyển. Nếu bạn làm điều đó, hãy nhớ rằng bạn không nên tham khảo bất kỳ mô hình bên ngoài hoặc thư viện trong ứng dụng của bạn từ đó, hoặc, nếu có bất kỳ cơ hội mà họ sẽ thay đổi trong tương lai. Điều này bao gồm cả đá quý và thậm chí có thể là một số lớp Ruby/Rails cốt lõi, bởi vì những thay đổi phá vỡ trong đá quý là rất phổ biến (tôi đang nhìn bạn, Rails 3.0, 3.1 và 3.2!).

0

Trong tình huống tương tự, tôi đã kết thúc việc thêm cột bằng cách sử dụng add_column và sau đó sử dụng SQL trực tiếp để cập nhật giá trị của cột. Tôi đã sử dụng SQL trực tiếp và không phải là mô hình cho mỗi Jim Stewart's answer, kể từ đó nó không phụ thuộc vào trạng thái hiện tại của mô hình so với trạng thái hiện tại của bảng dựa trên việc di chuyển đang chạy.

class AddColorToGroup < ActiveRecord::Migration 
    def up 
    add_column :groups, :color, :string 
    execute "update groups set color = case when is_active and is_live then 'red' when is_active then 'green' else 'orange' end" 
    end 

    def down 
    remove_column :groups, :color 
    end 
end 
Các vấn đề liên quan