Rails has_one vs belongs_to语义

我有一个模型表示包含一些图像的Content项。 图像的数量是固定的,因为这些图像参考非常特定于内容。 例如, Content模型两次引用Image模型(轮廓图像和背景图像)。 我试图避免genericshas_many ,并坚持多个has_one的。 当前的数据库结构如下所示:

 contents - id:integer - integer:profile_image_id - integer:background_image_id images - integer:id - string:filename - integer:content_id 

我在这里无法弄清楚如何正确设置关联。 Content模型可以包含对Image两个belongs_to引用,但是在语义上似乎不正确,因为理想情况下图像属于内容,或者换句话说,内容具有两个图像。

这是我能想到的最好的(通过打破语义):

 class Content belongs_to :profile_image, :class_name => 'Image', :foreign_key => 'profile_image_id' belongs_to :background_image, :class_name => 'Image', :foreign_key => 'background_image_id' end 

我离开了,有更好的方法来实现这种关联吗?

简单的答案是将您的关联设置为与您拥有的关联相反,如下所示:

 # app/models/content.rb class Content < ActiveRecord::Base has_one :profile_image, :class_name => 'Image' has_one :background_image, :class_name => 'Image' end # app/models/image.rb class Image < ActiveRecord::Base belongs_to :content end 

您根本不需要内容表中的外键'background_image_id'和'profile_image_id'。

但是,有一个更优雅的解决方案:单表inheritance。 现在进行设置,以防您希望将来背景和个人资料图像的行为略有不同,此外它将在今天澄清您的代码。

首先,在images表中添加一个名为type的列:

 # command line script/generate migration AddTypeToImages type:string rake db:migrate 

现在设置你的模型如下:

 # app/models/content.rb class Content < ActiveRecord::Base has_one :profile_image has_one :background_image end # app/models/image.rb class Image < ActiveRecord::Base belongs_to :content end # app/models/background_image.rb class BackgroundImage < Image # background image specific code here end # app/models/profile_image.rb class ProfileImage < Image # profile image specific code here end 

现在,您可以执行各种操作,例如获取所有背景图像的列表:

 # script/console BackgroundImage.all 

对于您尝试创建的数据模型更为正确,允许将来最简单的可扩展性,并为您提供一些很酷的新方法。

更新:

我之后创建了一篇名为Single-Table Inheritance with Tests的博客文章,该文章详细介绍了测试。

根据AR协会指南 ,我认为你应该使用has_one 。 拥有内容的图像没有意义……内容肯定拥有图像。 从指南:

区别在于您放置外键的位置(它在用于声明belongs_to关联的类的表中),但您应该考虑数据的实际含义。 has_one关系表明某事是你的 – 也就是说,有些东西指向你。

最后,我不确定你需要内容和图像都有外键。 只要图像引用content_id,我认为你没问题。