0

我有两个数据库表,houses并且apartments. 其中每一个都有自己的视图页面,我希望用户对其发表评论。当然,我也有一张posts桌子。创建帖子时,它应该有一个引用适当表的外键 id(要么 要么housesapartments。有没有一种有效的方法来为posts表创建某种类型的模棱两可的外键并在创建时定义它?到目前为止,我想到的问题的最佳解决方案是创建两个外键 id(一个 forhouses和一个 for apartments),并且每个post. 谢谢您的帮助!

4

2 回答 2

3

单表继承允许将对象定义为单独的类,同时仅使用单个数据库表。这适用于结构和功能相似的对象,除了轻微的行为差异。

在您的情况下,您有两个子类HouseApartment,它们非常相似,可以抽象为单个超类 ,Dwelling。这个超类将包含房屋和公寓都可以访问的通用方法。Dwelling每个子类都将使用自己的子类特定方法继承和扩展它。您将像往常一样实例化一个子类,但在内部 Rails 将使用超类的类型转换实例。因此,您永远不应该直接实例化超类。

值得注意的是,STI 将所有属性组合到一张表中。一个子类的属性将出现在另一个子类中,如果未使用则为零。具有大量无关属性的子类将导致填充nil值的臃肿表。作为一般规则,当您的子类包含的差异多于相似性时,应考虑多态关联。


这是我们的做法。所有这些都在app/models/dwelling.rb

class Dwelling < ActiveRecord::Base
  has_many :posts
  # ...common methods...
end 

class House < Dwelling
  has_many :posts, :foreign_key => "dwelling_id"
  # ...house methods...
end

class Apartment < Dwelling
  has_many :posts, :foreign_key => "dwelling_id"
  # ...apartment methods...
end

为了使它起作用,您的dwelling必须包含一个名为 "type" 的字符串列。Rails 会看到这一点并自动知道正在使用 STI。注意:应用程序将不再使用house和表。apartment创建一个House对象会将一个新的居住记录保存到数据库中,它有自己的唯一 ID,type它将是“房子”。

将新对象分配给Post子类时,请使用子类对象的 ID。子类 ID 和超类 ID 都引用相同的记录。请注意has_many每个子类中的方法。通过调用获取子类的帖子@house.posts

要推断帖子是发布到房屋还是公寓,您可以使用@post.dwelling.type.


编辑:

Rails 3 的自动加载行为要求每个类都在它自己的文件中。因此,子类必须分别在自己的文件中:

app/
  models/
    apartment.rb
    dwelling.rb
    house.rb
于 2013-04-10T01:37:06.570 回答
1

多态关联应该可以解决问题。您希望帖子引用房屋和公寓。您必须通过模型添加多态关联,然后为表添加适当的字段。

如果您确实决定采用多态路线,那么您的模型将是什么样子。

帖子

#Attributes
housing_type :string #Either will `House` or `Apartment`
housing_id :integer #This will reference the id of House or Apartment, depending on what's in your housing_type field

#Associations
belongs_to :housing, :polymorphic => true

房屋

#Attributes
post_id :integer

#Associations
has_many :posts, :as => :housing

公寓

#Attributes 
post_id :integer

#Associations
has_many :posts, :as => :housing

关于理解和创建多态关联的基本指南。

当然还有RailsCast

于 2013-04-10T00:50:04.193 回答