RoR:STI / MTI / Mixin 混淆

发布于 2024-10-23 19:36:10 字数 1653 浏览 7 评论 0原文

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

让我们举一个简单的例子,我将用面向 ORM 的语言而不是数据库/模型语言来讨论。

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

我尝试过做各种事情:

  • 第三方< ActiveRecord::基本
  • 客户 <第三方
  • 供应商<第三方

[编辑] 错过了我在这里的解释。我的意思是:第三方的一个实例可以是客户、供应商,两者都可以,也可以都不是。 正如第一个评论者指出的那样,我的例子可能不是最好的......您可以用“Character”替换“ThirdParty”,用“Archer”/“SwordsMan”替换“Customer”/“Supplier”。角色可以是一个、两个、两个或都没有,但会提供有关任何角色实例的信息。 Archer / SwordsMan 上的 getter 应返回“实现”接口契约的角色实例,而不是仅返回其自身的实例以及角色对象上的“getter”。 [/编辑]

我也尝试过:

  • ThirdParty < ActiveRecord::Base(有一个客户;有一个供应商)
  • 客户 < ActiveRecord::Base(属于第三方)
  • 供应商 < ActiveRecord::Base (belongs_to ThirdParty)

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

另外,我可以在我的第三方模型中包含 customer_id 和 seller_id 字段,但这似乎也不正确,因为一个第三方可以同时是两者,或者都不是......

当然,我希望能够找到一个不会造成阻碍/太多黑客的解决方案,例如允许我对另一个模型进行一些多态关联(例如可寻址、可评论、可联系等......)

我也一直在阅读很多有关该主题的内容,例如在此类博客上:http://mediumexposure.com/multiple -table-inheritance-active-record/ ...但是我迷失了正确的方法(在我找到的关于该主题的大多数文档中,不清楚是否适用于 Rails 1, 2、3...最近针对此事实施了什么,等等)。

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

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

PS:如果你需要我解释更多我正在寻找的内容,我可以尝试......但请记住,我的英语在这个领域有点“有限”,因为我对 RoR 相对较新。

i have a problem which is i believe basic for most of the RoR developers. In fact, it's more about "understanding" than really programming it (i have already been programming a few modules to be able to extend ActiveRecord::Base to allow easy generation of Ext-JS related things without any problem).

Let's take a simple example, i'll talk in an ORM oriented language rather than a database / model language.

  • ThirdParty is a basic entity, having a common member named 'label'.
  • A ThirdParty instance can be a Customer, a Supplier, both, or none of them (So Customer / Supplier are like concrete interfaces rather than inherited classes).
  • Both Customer and Supplier have specialized members, which are for most of them unique to each respective class (Customer / Supplier don't share much data except the label field they are bound to via ThirdParty).

i have tried to do various things:

  • ThirdParty < ActiveRecord::Base
  • Customer < ThirdParty
  • Supplier < ThirdParty

[EDIT]
Missed my explanation here. i meant: one single instance of ThirdParty could be a customer, a supplier, BOTH, OR NONE.
As the first commenter pointed out, my example might not be the best... You can replace "ThirdParty" by "Character", and "Customer" / "Supplier" by "Archer" / "SwordsMan". A character can either be one, two, both, or none, but would provide the information on any instance of Character. The getters on Archer / SwordsMan shall return instances of Character "implementing" the interface contract, rather than just returning an instance of themself with a "getter" on the character object.
[/EDIT]

Also i have tried:

  • ThirdParty < ActiveRecord::Base (has_one Customer; has_one Supplier)
  • Customer < ActiveRecord::Base (belongs_to ThirdParty)
  • Supplier < ActiveRecord::Base (belongs_to ThirdParty)

But it seems a bit "ugly" to me, because i have to do Customer.find(something).third_party.label to access data "inherited" by my "interfaces".

Also, i could include a customer_id and a supplier_id field on my ThirdParty model, but it doesn't seem right neither, because one ThirdParty can be both, or none of them...

And of course, i'd like to be able to find a solution which isn't obstructive / too much of a hack, to allow me for instance to then do some polymorphic association for another model (Such as an addressable, or commentable, contactable, etc...)

i also have been reading a lot on the subject like on such blog: http://mediumexposure.com/multiple-table-inheritance-active-record/ ... But i'am lost in the right way to do it (On most of the documentation i have found on the subject isn't clear if it's for Rails 1, 2, 3... What's recently been implemented on the matter, etc).

Can someone provide me with various "up-to-date" websites or to an example fitting the example i have given?

By advance, i thank you all for having red my question, and to edventually explain me the different techniques used regarding this particular subject.

P.S.: If you need me to explain more what i'm looking for, i can try... But keep in mind that my english is a bit "limited" on this domain, since i'm relatively new to RoR.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

牵你的手,一向走下去 2024-10-30 19:36:10

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

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

这允许您定义利用每个包含类的标签属性的方法。您提到您希望能够与其他模型交互,可能是多态的。如果这些关联存在于所有 ThirdParty 对象中,那么您只需在 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

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

Having only one field in common, single (or multiple) table inheritance probably isn't the way to go. If you want to share functionality between the classes I would create a ThirdParty module that gets included into each class:

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

This allows you to define methods that utilize the label attribute of each including class. You mention that you'd like to be able to interface with other models, possibly polymorphically. If these associations are present in all ThirdParty objects then you would just setup the associations in either the self.included call (using instance_eval) or in ClassMethods as a method:

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

Hopefully that helps. For more information on doing stuff like this just google "ruby mixin" - there's ton of info out there.

你丑哭了我 2024-10-30 19:36:10

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

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

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

本质上你可以有公共字段在您的 ThirdParty 类中并创建一个继承它们的 Customer 或Supplier 对象。

您可以创建一个包含两者都使用的函数的模块并在它们之间共享该模块吗?

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

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

I recently forked a promising project to implement multiple table inheritance and class inheritance in Rails. I have spent a few days subjecting it to rapid development, fixes, commenting and documentation and have re-released it as CITIER (Class Inheritance and Table Inheritance Embeddings for Rails).

I think you could potentially combine it with the answers above?

Consider giving it a look: http://peterhamilton.github.com/citier

Essentially you could have common fields in your ThirdParty class and create a Customer or Supplier object which inherits them.

You could create a module with functions used in both of them and share that between them?

CITIER wouldn't allow you to have a third party being a Customer and Supplier at the same time as it relies on Ruby inheritance which doesn't support Multiple inheritance. I would imagine some sort of shared module solution would make that part work?

In fact, CITIER already uses something similar to the answer above so would see the right track.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文