2012-07-26 28 views
25

On Rails 3.2.6, tôi có một lớp kế thừa từ ActiveRecord :: Base:Ngăn chặn STI khi kế thừa từ một mô hình ActiveRecord

class Section < ActiveRecord::Base 
    ... 
end 

Khi tôi kế thừa từ lớp này, Rails sẽ cho rằng tôi muốn STI:

class AnotherSection < Section 
    ..Rails assumes I have a type field, etc... 
end 

tôi muốn để có thể kế thừa từ lớp Section và sử dụng các lớp con như một lớp con của Ruby bình thường, không có sự kỳ diệu Rails STI.

Có cách nào để ngăn chặn STI khi phân lớp từ mô hình ActiveRecord::Base không?

+2

nếu bạn không có cột 'loại' không làm phiền bạn ... nếu bạn có' loại', thì bạn có thể tắt nó bằng cách làm những gì @Veraticus đã nói .. – shuriu

+0

Thực tế bạn vẫn còn có STI: các cá thể từ cả hai lớp sẽ được lưu trữ trong cùng một bảng, định nghĩa của STI (Thừa kế bảng đơn) là gì. Bạn chỉ không muốn có một cột phân biệt đối xử ("loại"). Tuy nhiên, làm thế nào bạn sẽ biết nếu mỗi bản ghi từ các phần là một phần đồng bằng hoặc một AnotherSection? – atorres

Trả lời

28

Bạn có thể đạt được điều này bằng cách tắt các inheritance_column cho mô hình, như vậy:

class AnotherSection < Section 
    # disable STI 
    self.inheritance_column = :_type_disabled 

end 
+7

Điều đó, hoặc bất kỳ cột nào không tồn tại đủ. – shuriu

+3

self.inheritance_column = nil làm việc cho tôi (nhưng tôi đã thử nó từ lâu rồi và nó là đường ray 3.2) – Alexis

+0

điều này vô hiệu hóa cột phân biệt đối xử. Nhưng cả hai lớp được lưu trữ ở cùng một bảng, định nghĩa của STI (Inheritance bảng đơn) là gì. Bạn chỉ cần loại bỏ cột phân biệt đối xử và ruby ​​sẽ không thể quyết định loại bản ghi được lưu trữ (bạn sẽ cần quyết định khi tải) – atorres

11

Câu trả lời được chấp nhận sẽ chắc chắn làm việc, nhưng đề xuất (tôi dám nói "đúng" :) cách là để thiết lập abstract_class :

class Section < ActiveRecord::Base 
    self.abstract_class = true 
end 
+3

Đây là cách tiếp cận chính xác và đã có từ Rails 1.1. –

+0

Điều này không hiệu quả đối với tôi. Tôi không thể khởi tạo bất kỳ đối tượng nào của lớp mô hình này ... ('NotImplementedError: MyModel là một lớp trừu tượng và không thể được instantiated.'). Vì vậy, vui lòng sửa đổi câu trả lời của bạn @smathy – deepflame

+0

@deepflame bạn không thể khởi tạo một lớp trừu tượng, nó trừu tượng. – smathy

1

Chiến lược duy nhất được hỗ trợ đầy đủ để lưu trữ kế thừa trên ActiveRecord là STI. Tuy nhiên, bạn có thể mô phỏng sự thừa kế bảng lớp bê tông theo nguy cơ của riêng bạn. Việc thừa kế bảng lớp bê tông với lớp cha trừu tượng hoạt động tốt, như được chỉ ra bởi sự cảm thông.

NHƯNG ... Nếu điều bạn muốn là làm cho AnotherSection chỉ là một lớp thông thường (sẽ không được lưu giữ tại cơ sở dữ liệu), bạn có thể vô hiệu hóa cột phân biệt đối xử (theo gợi ý của Veraticus). Tuy nhiên, nếu bạn lưu AnotherSection, nó sẽ được lưu giữ trong cùng một bảng với Phần và bạn sẽ không thể phân biệt chúng với nhau. Ngoài ra, nếu bạn sử dụng AnotherSection để tìm một Mục, nó sẽ trả về một AnotherSection, phá vỡ instantiation gốc:

#create a Section and saves it 
    sect = Section.create() 
    sect.save() 
    #retrieve the Section as a AnotherSection, breaking polymorphism... 
    sect = AnotherSection.find(sect.id) 
    # another section is more than a section, it is inconsistent. 

Nếu AnotherSection không có ý định để được tiếp tục tồn, con đường an toàn nhất nó để ghi đè các hoạt động liên tục, chẳng hạn như save() và tìm():

class AnotherSection < Section 
     # disable STI, as pointed by Veraticus 
     self.inheritance_column = :_type_disabled 
     # disable save and finding 
     def save(*args) 
     #exception? do nothing? 
     end 
     def find(*args) 
     #exception? do nothing? 
     end 
     def find_by(*args) 
     #exception? do nothing? 
     end 
     # this does not stops here! there is first, last, and even a forty_two finder method! not to mention associations... 
    end 

Tóm lại, bạn có thể làm điều này, nhưng bạn KHÔNG NÊN. Nguy cơ cao. Bạn nên xem xét một tùy chọn khác, chẳng hạn như sử dụng MIXIN thay vì thừa kế.

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