RoR: has_one “or the other”? (Or, polymorphism without the inheritance.)

折月煮酒 提交于 2019-12-20 21:23:26

问题


Hey all, I have something of an interesting requirement for my project. I need a has_one relationship where it is either one class or the other, but without inheritance. I could get away with inheritance if it is the only way, but the two associate records have completely different data and aren't related at all.

What I need to figure out is something like the following.

# 1. Foo never belongs to anything.
# 2. Foo MUST have one assigned sub-record for validity.
# 3. Foo can only have either Bar or Baz assigned.
# 4. Bar and Baz have only ONE common property, and aren't
#    related in either data or implementation.

class Foo < ActiveRecord::Base
  # Attributes: id, name, value
  has_one :assignment, :foreign_key => 'assigned_to', :readonly => true
          # Could really use an :object_type for has_one here...
end

class Bar < ActiveRecord::Base
  # Attributes: name,...
end

class Baz < ActiveRecord::Base
  # Attributes: name,...
end

Where Foo has one assignment, of type either Bar or Baz; they only share one common column, so perhaps I can make a parent object from that. However, if I make them inherit from a common object (when the data they contain really is oranges and apples) must I make a table for the record? Can I perhaps get away with it if the record is an abstract record, but the children aren't?

I suppose by now you can see my difficulty. I'm rather new to RoR but loving it so far. I'm sure there's a way around this, but I'll be darned if I can't figure out what it is.


回答1:


You're trying to model something that doesn't fit the relational database paradigm. All references in SQL have one origin and one target.

FWIW, Polymorphic Associations is also an anti-pattern because it breaks this rule. It should be a clue that it's a broken design when the documentation says you must forgo a referential integrity constraint to make it work!

You need Foo to have two has_one relationships: one to Bar and one to Baz. Then implement some class logic to try to ensure only one reference is populated in any instance of Foo. That is, of the references to Bar and Baz, one must have a value and the other must be nil, but this is something for your code to check for and enforce.




回答2:


Perhaps one way to do this, is to create to has-one associations in Foo, for Bar and Baz. Then create a method called assignment and assignment= which can be the sole way to access Bar and Baz. You can check which of the two has_ones is not nil in the get method and return that one. In the assignment method, you can-check what is the type of the variable passed in and set the correct has-one relationship to that object and set the other to nil. That ought to cover all your bases without being too complicated.



来源:https://stackoverflow.com/questions/375083/ror-has-one-or-the-other-or-polymorphism-without-the-inheritance

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!