我有两个数据库表,houses
并且apartments
. 其中每一个都有自己的视图页面,我希望用户对其发表评论。当然,我也有一张posts
桌子。创建帖子时,它应该有一个引用适当表的外键 id(要么 要么houses
)apartments
。有没有一种有效的方法来为posts
表创建某种类型的模棱两可的外键并在创建时定义它?到目前为止,我想到的问题的最佳解决方案是创建两个外键 id(一个 forhouses
和一个 for apartments
),并且每个post
. 谢谢您的帮助!
2 回答
单表继承允许将对象定义为单独的类,同时仅使用单个数据库表。这适用于结构和功能相似的对象,除了轻微的行为差异。
在您的情况下,您有两个子类House
和Apartment
,它们非常相似,可以抽象为单个超类 ,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
多态关联应该可以解决问题。您希望帖子引用房屋和公寓。您必须通过模型添加多态关联,然后为表添加适当的字段。
如果您确实决定采用多态路线,那么您的模型将是什么样子。
帖子
#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。