Các liên kết ActiveRecord, has_many: through và Polymorphic


117

Folks,

Muốn chắc chắn rằng tôi hiểu điều này một cách chính xác. Và vui lòng bỏ qua trường hợp kế thừa ở đây (SentientBeing), thay vào đó cố gắng tập trung vào các mô hình đa hình trong has_many: thông qua các mối quan hệ. Điều đó nói rằng, hãy xem xét những điều sau ...

class Widget < ActiveRecord::Base
  has_many :widget_groupings

  has_many :people, :through => :widget_groupings, :source => :person, :conditions => "widget_groupings.grouper_type = 'Person'"
  has_many :aliens, :through => :widget_groupings, :source => :alien, :conditions => "video_groupings.grouper_type = 'Alien'"
end

class Person < ActiveRecord::Base
  has_many :widget_groupings, :as => grouper
  has_many :widgets, :through => :widget_groupings
end

class Alien < ActiveRecord::Base
  has_many :widget_groupings, :as => grouper
  has_many :widgets, :through => :widget_groupings  
end

class WidgetGrouping < ActiveRecord::Base
  belongs_to :widget
  belongs_to :grouper, :polymorphic => true
end

Trong một thế giới hoàn hảo, tôi muốn, được trao một Widget và một Người, làm những điều như:

widget.people << my_person

Tuy nhiên, khi tôi làm điều này, tôi nhận thấy 'loại' 'cá mú' luôn rỗng trong widget_groupings. Tuy nhiên, nếu tôi làm như sau:

widget.widget_groupings << WidgetGrouping.new({:widget => self, :person => my_person}) 

Sau đó, tất cả hoạt động như tôi thường mong đợi. Tôi không nghĩ rằng tôi đã từng thấy điều này xảy ra với các liên kết không đa hình và chỉ muốn biết liệu đây có phải là điều gì đó cụ thể cho trường hợp sử dụng này hay tôi có khả năng đang nhìn chằm chằm vào một lỗi.

Cảm ơn vì bất kì sự giúp đỡ!

Câu trả lời:


162

Có một vấn đề đã biết với Rails 3.1.1 làm hỏng chức năng này. Nếu bạn gặp sự cố này, trước tiên hãy thử nâng cấp, nó đã được khắc phục trong 3.1.2

Bạn đang rất gần. Vấn đề là bạn đang sử dụng sai tùy chọn: source. : nguồn nên trỏ đến mối quan hệ thuộc_to đa hình. Sau đó, tất cả những gì bạn cần làm là chỉ định: source_type cho mối quan hệ mà bạn đang cố gắng xác định.

Bản sửa lỗi này cho mô hình Widget sẽ cho phép bạn thực hiện chính xác những gì bạn đang tìm kiếm.

class Widget < ActiveRecord::Base
  has_many :widget_groupings

  has_many :people, :through => :widget_groupings, :source => :grouper, :source_type => 'Person'
  has_many :aliens, :through => :widget_groupings, :source => :grouper, :source_type => 'Alien'
end

Ôi chúa ơi, điều đó rõ ràng đến mức đau đớn, tôi không thể tin rằng mình đã nhìn chằm chằm vào nó. Cảm ơn EmFi!
Cory

Không sao, tôi nghĩ rằng tôi đã đau đớn trong khoảng một ngày về cách làm điều này trong lần đầu tiên tôi gặp nó. Không giúp được gì rằng đó là một trong những điều đầu tiên tôi cố gắng làm trong Rails mà không liên quan đến việc làm theo một hướng dẫn / sách.
EmFi

1
Như scotkf đã chỉ ra, có một hồi quy trong ActiveRecord 3.1.1 chặn hành vi này. Nâng cấp lên 3.1.2 sẽ cho phép giải pháp này hoạt động.
EmFi

6
Điều tương tự như những gì @Shtirlic đã đề cập. Có cách nào để không chỉ định source_type, vì vậy bạn có tập hợp kết quả hỗn hợp không? Nếu có ai giải quyết được điều này, rất muốn biết cách làm.
Damon Aw

3
Vẫn hoạt động như Rails 4.2.0. Tuy nhiên, có cách nào để thực hiện điều này những ngày này mà không có source_type và hai liên kết riêng biệt không?
Emeka

3

Như đã đề cập ở trên, điều này không hoạt động với rails 3.1.1 do lỗi trên: source, nhưng nó đã được sửa trong Rails 3.1.2


-4

có nhiều: thông qua và đa hình không hoạt động cùng nhau. Nếu bạn cố gắng truy cập trực tiếp vào chúng, nó sẽ xuất hiện một lỗi. Nếu tôi không nhầm, bạn phải viết tay widget.people và quy trình đẩy.

Tôi không nghĩ đó là một lỗi, nó chỉ là một cái gì đó chưa được triển khai. Tôi sẽ tưởng tượng rằng chúng ta sẽ thấy nó trong tính năng, bởi vì mọi người đều có trường hợp mà họ có thể sử dụng nó.


6
Họ làm việc cùng nhau. Ví dụ: has_many:
subscribe,:

Tôi sẽ đưa ra một ví dụ về mã lỗi của tôi như một bài đăng riêng trong tương lai gần :) Nó sẽ giúp tôi tiết kiệm rất nhiều đau đầu để tìm ra cách vượt qua lỗi đó.
cgr
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.