【问题标题】:"Virtual Relationships" in RailsRails 中的“虚拟关系”
【发布时间】:2011-06-10 23:21:24
【问题描述】:

我正在尝试在 Rails 中建立“虚拟关系”(我称之为 - 不知道是否有真正的术语)。这是我拥有的一个绝对有效的方法:Address belongs_to BusinessBusiness has_many Addresses地址有一个“类别”列:MailingPhysical。理论上,一家企业可以拥有任意数量的每种类型,但实际上它们只有一种。所以我的模型看起来像这样:

class Address < ActiveRecord::Base
  belongs_to :business
end

class Business < ActiveRecord::Base
  has_many :addresses
  has_one  :physical_address, :class_name => 'Address', :conditions => ["category = ?", "Physical"]
  has_one  :mailing_address, :class_name => 'Address', :conditions => ["category = ?", "Mailing"]
end

因此,我有两个“虚拟”has_one,因此我可以方便地访问其中一个(如 business.physical_addressbusiness.mailing_address),而无需执行自己分离它们的工作。

现在我正在尝试做类似的事情,但使用 has_many :through。这是我的新场景。我与连接有一个简单的多对多关系。假设A有很多JB也有很多JJ 属于 AB。然而,A 也有_many 个BJ。所以我可以以 a.bs 的身份访问它们。

但是,B 中的条目也有一个“类别”。因此,与上面的 Business/Address 示例一样,我希望在 A 中具有“虚拟”具有单通/多通的关系,因此我不必手动按类别分开B。我尝试过这样的事情(假设 A 正好有一个 B 的 category='Type 1'):

class A < ActiveRecord::Base
  has_many :js
  has_many :bs, :through => js
  has_one  :b_type1, :class_name => 'B', :through => :js, :conditions => ["category = ?", "Type 1"]
end

但是,当我在 A 上进行查找时,结果对象中没有 b_type1 属性。

甚至有可能做我想做的事吗?任何帮助表示赞赏。

编辑:我需要将其序列化到 Adob​​e Flex 前端(使用 RestfulX 框架)。根据this thread,我不能只使用@Andrew 在下面建议的方法,因为如果不进行一些繁重的工作,生成的对象将无法正确序列化。

【问题讨论】:

  • 你正在尝试做的有多态关系和单表继承方面,这两个 Rails 都支持。这些主题很广泛,并且在网络上的其他地方广为流传。谷歌搜索一下如何在 Rails 中做这两件事,我想你会找到你想要的。
  • 不,这与多态无关。 JAB 之间的连接表,而不是 J 在多态上属于任一 A i> 或 B.
  • 对不起,我读到“...and J belongs_to both A and B”表示下午。

标签: ruby-on-rails syntax virtual relationships


【解决方案1】:

您编写的 has_one 关联应该完全按照您的意愿工作,但是 Rails 将无法从 :b_type1 猜测该字段。

就像你明确指定类名一样,尝试指定源:

has_one :b_type1, :class_name => 'B', :through => :js, :source => bs, :conditions => ["category = ?", "Type 1"]

我测试了一个类似的查找器,它的工作方式与您期望的一样。

【讨论】:

  • 好的,我会用 :source 试试看会发生什么。我今天搞砸了很多,发现 :source,但是在我尝试过的所有组合中,我并没有完全按照这种方式尝试。
  • 是的,似乎只要添加 :source 就可以了。我想我真的很接近。一件事(我将编辑 OP 以反映这一点)是我需要将此值序列化到 Flex 前端。所以也许我在某个时候做对了,只是没有正确序列化它。无论如何,这似乎解决了问题。谢谢!
【解决方案2】:

我可以想到两种“更可靠”的方法来解决这个问题。

第一种方式:为什么不直接制作这些方法呢?

在您给出的第一个示例中,在您的 Business 课程中尝试:

def physical_address
   self.address.where(:category => 'physical').first
end

现在调用business.physical_address 将返回地址对象。以同样的方式,您可以通过您的 HABTM 关联执行此操作。

class A < ActiveRecord::Base
  ...
  def type_1
    self.bs.where(:category=>'type_1').first
  end
  ...
end

现在调用 a.type_1 将返回具有“Type_1”类别的单个 B(如果有多个,则返回第一个)。

第二种方式:如果您认为给定的“虚拟关系”会有多个匹配项,则更有用的是,您可以将这些条件设为范围。所以,对于第二个例子:

class B < ActiveRecord::Base
  ...
  scope :type_1 { where(:category=>'type_1') }
  ...
end

现在,如果您致电 a.bs.type_1.first,您将得到您正在寻找的 B。如果您永远不会有多个,您也可以将.first 放在范围内。

要强制只有一个,您还可以创建一个uniqueness validation,使用给定的父对象验证类别的唯一性。

在我看来,使用这些选项中的任何一个都比建立这些“虚拟”关系更接近解决问题的“Rails 方式”。也许只是我。

请试试这个,如果你有任何问题,请告诉我:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-11
    • 2013-01-08
    • 2012-10-11
    • 1970-01-01
    相关资源
    最近更新 更多