【问题标题】:Rails has_one vs belongs_to semanticsRails has_one vs belongs_to 语义
【发布时间】:2010-01-25 22:18:26
【问题描述】:

我有一个模型代表一个包含一些图像的Content 项目。图像的数量是固定的,因为这些图像引用非常特定于内容。例如,Content 模型两次引用Image 模型(个人资料图像和背景图像)。我试图避免使用通用的has_many,并坚持使用多个has_one。当前的数据库结构如下:

contents
  - id:integer
  - integer:profile_image_id
  - integer:background_image_id

images
  - integer:id
  - string:filename
  - integer:content_id

我只是不知道如何在这里正确设置关联。 Content 模型可以包含两个 belongs_toImage 的引用,但这在语义上似乎不正确,因为理想情况下图像属于内容,或者换句话说,内容有两个图像。

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

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

我离得远吗,还有更好的方法来实现这种关联吗?

【问题讨论】:

    标签: ruby-on-rails model associations


    【解决方案1】:

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

    # 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”。

    不过,有一个更优雅的解决方案: 单表继承。现在就设置它,以防您希望背景和个人资料图像在未来表现得稍有不同,而且它会在今天澄清您的代码。

    首先,在图像表中添加一个名为 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 的博客文章,其中更详细地介绍了测试。

    【讨论】:

    • 单表继承非常适合我的问题。您知道如何将 STI 与多态关联集成吗?例如,如果与内容一起,有一些图像是文档元数据的一部分,并且内容和元数据图像都存储在图像表中。
    • 非常感谢这篇文章。那一定是网上关于 Rails 单表继承的最佳文章!
    • 对于“简单的答案”,如果 db 表中没有外键,Content 如何知道要引用哪些图像?
    • 链接失效了。
    【解决方案2】:

    基于the AR associations guide,我认为你应该使用has_one。图像拥有内容是没有意义的……内容肯定拥有图像。来自指南:

    区别在于您放置的位置 外键(它放在桌子上 对于声明belongs_to的类 协会),但你应该给一些 考虑到实际意义 数据也是如此。 has_one 关系 说一件东西是你的—— 也就是说,有些东西指向 你。

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

    【讨论】:

      猜你喜欢
      • 2014-10-01
      • 2014-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多