2010-07-09 36 views
5

Giả sử tôi có đối tượng FireNinja < Ninja trong cơ sở dữ liệu của mình, được lưu trữ bằng cách sử dụng thừa kế bảng đơn. Sau đó, tôi nhận ra anh ta thực sự là một WaterNinja < Ninja. Cách sạch nhất để thay đổi anh ta thành lớp con khác là gì? Thậm chí tốt hơn, tôi rất muốn tạo một đối tượng WaterNinja mới và chỉ thay thế số FireNinja cũ trong DB, giữ lại ID.Thay đổi lớp của đối tượng trong ActiveRecord

Sửa tôi biết làm thế nào để tạo ra các đối tượng mới WaterNinja từ hiện FireNinja, và tôi cũng biết tôi có thể xóa cái cũ và lưu mới của tôi. Điều tôi muốn làm là biến đổi lớp của mục hiện có. Cho dù tôi làm điều đó bằng cách tạo ra một đối tượng mới và thực hiện một số phép thuật ActiveRecord để thay thế hàng, hoặc bằng cách làm một điều điên rồ nào đó cho chính đối tượng đó, hoặc thậm chí bằng cách xóa nó và gắn lại với cùng một ID là một phần của câu hỏi.

Trả lời

2

Bạn cần phải làm hai việc:

  • Tạo WaterNinja < Ninja
  • Trong ninjas bảng chạy cái gì đó như UPDATE ninjas SET (type = 'WaterNinja') WHERE (type = 'FireNinja')

Đó là về nó.

Để thực hiện chuyển đổi thời gian chạy, thao tác này sẽ thực hiện, nhưng tôi không khuyến nghị.

class Ninja 
    def become_another_ninja(new_ninja_type) 
    update_attribute(:type, new_ninja_type) 
    self.class.find(id) 
    end 
end 

@water_ninja = @fire_ninja.become_another_ninja('WaterNinja') 

Vấn đề ở đây là bây giờ @fire_ninja sẽ là một throwaway đối tượng .

+0

Có vẻ như bạn đang trả lời, "làm cách nào để chuyển đổi tất cả' FireNinjas' thành 'WaterNinjas'?" Câu trả lời vẫn hoạt động mặc dù nếu tôi thay đổi điều kiện thành 'ID = myid'. Vâng, tôi đã nghĩ về điều đó.Tôi cũng phải kéo đối tượng ra sau khi cập nhật để làm một số thiết lập trường cụ thể WaterNinja, nhưng đó là tốt. Tôi đã hy vọng cho một cái gì đó một chút sạch hơn, mặc dù. –

+0

Tôi hiểu ý của bạn là gì. Tôi không khuyên bạn nên làm điều này, nhưng điều này sẽ làm các trick: 'ninja_id = @ ninja.id; @ ninja.update_attribute (: type, 'WaterNinja'); @ninja = WaterNinja.find (ninja_id) ' –

+0

Đã chỉnh sửa để hiển thị phương pháp tôi mô tả. –

-1

Bạn sẽ phải xác định phương thức WaterNinja#to_fireninja. Ruby không có cách nào để thay đổi lớp của một đối tượng trong khi vẫn giữ nó cùng một đối tượng.

class WaterNinja < Ninja 
    def to_fireninja 
    FireNinja.new :name => name 
    end 
end 
+0

Điều đó sẽ tạo đối tượng mới, nhưng khi tôi gọi lưu, nó sẽ tạo một hàng khác trong cơ sở dữ liệu. Tôi muốn thay thế thể hiện FireNinja của mình bằng đối tượng WaterNinja mới. –

+0

@ Isaac: Tôi không nghĩ rằng có thể, trừ khi bạn có thể xóa WaterNinja và buộc ActiveRecord để lưu FireNinja mới với cùng một ID. – Adrian

+0

một cách câu hỏi có thể được trả lời là nếu bạn có thể cho tôi biết làm thế nào để lưu các ninja mới với một ID hiện có. Tôi rất sẵn lòng xóa và lắp lại. –

0

Thành phần ưu tiên hơn thừa kế - bạn nên sử dụng mẫu chiến lược để thay đổi loại hành vi này khi chạy.

http://en.wikipedia.org/wiki/Strategy_pattern

+0

Không nhất thiết. Google cho "thay thế loại hình đa hình" và "thay thế kiểu với chiến lược" mô hình tái cấu trúc. Sử dụng chiến lược bao gồm một số trường hợp, nhưng trong những người khác, người ta muốn thừa hưởng. Các mẫu này cũng được mô tả tốt trong sách Tái cấu trúc (http://www.amazon.com/Refactoring-Ruby-Jay-Fields/dp/0321603508). – samuil

+0

Tôi có lý do chính đáng để sử dụng thừa kế độc lập với vấn đề tôi trình bày ở trên. Tôi không xây dựng changetypeofninja.com. –

7

Bạn có thể thực hiện hành động FireNinja bạn như là một WaterNinja bằng cách làm

@ninja.becomes(WaterNinja) 

Nếu bạn muốn vĩnh viễn thay đổi lớp học, sau đó chỉ cần ghi đè lên các thuộc tính type.

@ninja.type = "WaterNinja" 
@ninja.save! 
+0

Đây là câu trả lời đúng, câu trả lời được chấp nhận không tốt vì nó không sử dụng "trở thành" – Rob

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