【问题标题】:RoR: STI / MTI / Mixin confusionRoR:STI / MTI / Mixin 混淆
【发布时间】:2011-07-17 19:28:56
【问题描述】:

我有一个问题,我认为这对大多数 RoR 开发人员来说是基本的。事实上,它更多的是关于“理解”而不是真正的编程(我已经编写了一些模块来扩展 ActiveRecord::Base 以允许轻松生成与 Ext-JS 相关的东西而没有任何问题)。

我们举个简单的例子,我会用面向 ORM 的语言而不是数据库/模型语言。

  • ThirdParty 是一个基本实体,有一个名为“label”的通用成员。
  • ThirdParty 实例可以是客户、供应商,或者两者都不是(因此客户/供应商就像具体的接口,而不是继承的类)。
  • Customer 和 Supplier 都有专门的成员,其中大多数成员对每个类都是唯一的(除了通过第三方绑定的标签字段外,客户/供应商不共享太多数据)。

我尝试过做各种各样的事情:

  • 第三方<:base>
  • 客户
  • 供应商

[编辑] 在这里错过了我的解释。我的意思是:第三方的一个实例可能是客户、供应商、两者或无。 正如第一位评论者指出的那样,我的示例可能不是最好的......您可以将“第三方”替换为“角色”,将“客户”/“供应商”替换为“弓箭手”/“SwordsMan”。一个字符可以是一个、两个、两者或无,但会提供有关任何 Character 实例的信息。 Archer / SwordsMan 上的 getter 应返回“实现”接口契约的 Character 实例,而不是仅返回他们自己的实例,并在角色对象上使用“getter”。 [/编辑]

我也试过了:

  • 第三方
  • 客户 <:base thirdparty>
  • 供应商

但这对我来说似乎有点“丑陋”,因为我必须执行 Customer.find(something).third_party.label 才能访问我的“接口”“继承”的数据。

另外,我可以在我的 ThirdParty 模型中包含 customer_id 和 supplier_id 字段,但这似乎也不对,因为一个 ThirdParty 可以两者兼有,或者都不是...

当然,我希望能够找到一个不会造成阻碍/没有太多技巧的解决方案,例如,让我可以为另一个模型做一些多态关联(例如可寻址,或可评论、可联系等...)

我也一直在阅读很多关于这个主题的文章,比如在这样的博客上:http://mediumexposure.com/multiple-table-inheritance-active-record/ ...但我迷失在正确的方式上(在我找到的关于这个主题的大多数文档中)不清楚它是否适用于 Rails 1、2、3……最近在这件事上实施了什么,等等)。

有人可以为我提供各种“最新”网站或适合我给出的示例的示例吗?

在此先感谢大家提出我的问题,并最终向我解释在这个特定主题上使用的不同技术。

PS:如果您需要我解释更多我在寻找什么,我可以尝试......但请记住,我的英语在这个领域有点“有限”,因为我对 RoR 比较陌生.

【问题讨论】:

  • CustomerSupplier 之间真的有足够的共同点来保证类层次结构可以加入它们吗?听起来您有一个在它们之间共享的成员字段,这感觉就像很多机器可以避免一个字段的重复。
  • 我的例子其实只是一个例子。假设它是一个游戏角色系统,那么......角色可以是弓箭手,剑士等。所有这些,或者没有它们,但它仍然是一个“人”角色。我只想看到一个与示例匹配的解决方案,以更好地代表我自己如何实现它。
  • 皮埃尔,谢谢,我现在明白了:) 你的第二个例子也很好,但我真的无法提出比你尝试过的更好的建议。 :)
  • 没问题,感谢您的阅读;)
  • 在您的 sti 示例中 Customer.all 应该只返回客户,而不是所有第三方。确保添加类型列。

标签: ruby-on-rails model polymorphic-associations mixins sti


【解决方案1】:

只有一个共同的字段,单(或多)表继承可能不是要走的路。如果您想在类之间共享功能,我将创建一个包含在每个类中的第三方模块:

module ThirdParty
  def self.included(base)
    base.extend ClassMethods
  end

  module ClassMethods
    # define your shared class methods here
  end

  # define you shared instance methods down here
end

class Customer < ActiveRecord::Base
  include ThirdParty
end

class Supplier < ActiveRecord::Base
  include ThirdParty
end

这允许您定义利用每个包含类的标签属性的方法。您提到您希望能够与其他模型交互,可能是多态的。如果这些关联存在于所有第三方对象中,那么您只需在 self.included 调用(使用 instance_eval)或 ClassMethods 作为方法中设置关联:

module ThirdParty
  def self.included(base)
    base.extend ClassMethods
    base.instance_eval do
      has_many :buyers, :as => :third_party
    end
  end

  module ClassMethods
    def has_address
      has_one :address, :as => :third_party
      delegate :street, :city, :state, :zip, :to => :address
    end
  end
end

class Supplier < ActiveRecord::Base
  include ThirdParty # this would set up the :buyers association

  has_address # this sets up the address association
end

希望这会有所帮助。有关执行此类操作的更多信息,只需 google “ruby mixin” - 那里有大量信息。

【讨论】:

    【解决方案2】:

    我最近创建了一个很有前途的项目,在 Rails 中实现多表继承和类继承。我花了几天时间对其进行快速开发、修复、评论和文档,并将其重新发布为 CITIER(Rails 的类继承和表继承嵌入)。

    我认为您可以将其与上述答案结合起来吗?

    考虑看看:http://peterhamilton.github.com/citier

    基本上,您可以在第三方类中拥有公共字段并创建继承它们的客户或供应商对象。

    您可以创建一个模块,其中包含两者都使用的功能并在它们之间共享?

    CITIER 不允许您同时拥有第三方作为客户和供应商,因为它依赖于不支持多重继承的 Ruby 继承。我会想象某种共享模块解决方案可以使这部分工作?

    事实上,CITIER 已经使用了与上面的答案类似的东西,所以会看到正确的轨道。

    【讨论】:

    • 这颗宝石似乎没有得到很好的维护
    • 同意,我一直在开发一个新版本,但目前的版本已经有一段时间没有维护了,我非常依赖社区的意见。我希望它在未来变得更加稳固,从而更具商业可行性。
    猜你喜欢
    • 2019-12-22
    • 1970-01-01
    • 2014-07-09
    • 1970-01-01
    • 2014-05-06
    • 2015-02-02
    • 2011-05-11
    • 2012-06-02
    • 2012-08-15
    相关资源
    最近更新 更多