0

我有一个标准的多态关系设置,如:

#Foo
has_many: bar, as: foobar

#Qux
has_many: bar, as: foobar

#Bar
belongs_to :foobar, polymorphic: true

我希望能够强制执行has_many: bar, as: foobar具有某些属性的模型,例如 a name,因此我可以执行以下操作:

bar.foobar.name

并且知道此时 foobar 的型号并不重要。(因为所有的 foobars 都有一个 name 属性)

有没有办法做到这一点,或者responds_to?每次我想使用它时我都必须对其进行测试。

4

1 回答 1

1

您可以通过创建FooQux扩展的基类来提供默认值。代替

class Foo < ActiveRecord::Base
  has_many: bar, as: foobar
end

class Qux < ActiveRecord::Base
  has_many: bar, as: foobar
end

你可以做类似的事情

class Foobar < ActiveRecord::Base
  has_many: bar, as: foobar
end

class Foo < Foobar; end

class Qux < Foobar; end

然后,您可以为那些希望与扩展的类保持一致的属性创建一个默认访问器方法Foobar

class Foobar < ActiveRecord::Base
  has_many: bar, as: foobar

  def name
    "some default name"
  end
end

class Foo < Foobar
  def name
    "some overloaded name for Foo"
  end
end

class Qux < Foobar; end

name您可以如上所示重载Foo,或如所示省略它Qux。无论如何,一个name属性将可用,即使它只是来自Foobar.

foo = Foo.new
puts foo.name  # "some overloaded name for Foo"

qux = Qux.new
puts qux.name # "some default name"

如果您希望像其他语言一样通过接口或抽象类创建更多合同,Ruby 也不支持。但是,您可以使用包含在其中的 mixin,Foo如果未定义Qux则抛出异常。在此处阅读此类实现的示例name

请注意,这些模型应该在表中具有关联name列的可能性,您可能希望read_attribute(:name)在重载name方法中的某个位置合并。请参阅上的文档read_attribute

于 2012-11-02T18:05:07.997 回答