【问题标题】:foreign_key: belongs_to & has_one difference外键:belongs_to 和 has_one 的区别
【发布时间】:2015-06-08 21:09:45
【问题描述】:

我不明白这两种关联类型的区别。

例如,我们有 2 个表:

拳击手

[ id, name, title ]

标题

[ id, name ]

所以,我们可以这样指定我们的关联:

boxer.rb

belongs_to :title, forign_key: "title"

然后像 Boxer.find(1).title.name 一样使用它

从逻辑上讲,每个拳击手总是有一个冠军记录,每个冠军都有很多拳击手。

那么我们为什么不指定has_onehas_many 关系呢?当我指定belongs_to :title, forign_key: "title" 时,这意味着在我的情况下,FK 指向桌上拳击手(boxer.rb)。但是当我尝试写has_one :title, forign_key: "title" 时,它会在titles 表中搜索title 列。为什么?

【问题讨论】:

    标签: ruby-on-rails ruby associations models


    【解决方案1】:

    您将带有外键索引的模型上的belongs_to 放入另一个模型中。在另一个模型上,您放置了has_one。两者都允许您覆盖 fk 列的名称,但它始终在带有belongs_to 的表中。

    我用这个技巧来记住:

    一只狗belongs_to他的主人(不是相反),主人has_one狗。狗佩戴带有主人号码的 id 标签,而不是相反。

    【讨论】:

      【解决方案2】:

      一般来说,如果你不提任何事情,只需写下以下内容:

      class Boxer < ActiveRecord::Base
        belongs_to :title
      end
      

      然后你做:

      boxer = Boxer.find_by_id(1)
      puts boxer.title 
      

      boxer.title;它进入titles 表,并在那里搜索id 与存储在您调用方法boxer.title 的对象中的boxer_id 相同的行。

      当您没有在模型中指定 foreign_key 时会出现这种情况。

      但是,如果您确实指定了 foreign_key,如下所示:

      class Boxer < ActiveRecord::Base
        belongs_to :title, foreign_key: 'title'
      end
      

      现在,在boxers 表中,必须有一个列title 将存储它所属的标题的id

      区别只是:如果你没有指定foreign_key,它会去寻找title_id,但是当你指定foreign_key时,它会搜索那个。

      【讨论】:

      • 是的,我明白这一切,但问题是关于 has_one。在 has_one 关联中指定 FK 时,FK 的行为有所不同。它在其他表中搜索您使用 FK 指定的列。所以has_one :title, foreign_key: 'title' 不会在boxers 中搜索title,而是在titles 表中搜索。我不明白为什么?
      • 外键始终存在于属于其他表的表中。比如一台电脑belongs_to一个用户,外键就存在于电脑中。在你的情况下,titlebelongs_toboxer,所以显然外键应该存在于titles 表中,这就是它存在的地方。
      • 好的,知道了。但是has_one 呢,它期望 FK?
      • 就像你的情况一样,boxer has_one title,所以默认情况下boxer 将在titles 表中查找名为boxer_id 的键,而不是在boxers 表中。当你说拳击手has_one :title, foreign_key: title 时,那个名为boxer_id 的键现在将被简单地替换为title 键,因为这就是你在代码中提到的。永远记住,FK存在于belongs_to另一张表的表中。
      • 最重要的是,如果你在title模型中指定了foreign_key,你还必须在其他模型中指定相同的foreign_key:Boxer,否则它不适用于当前场景。
      【解决方案3】:

      我认为这种混淆可能源于您的模型之间的关联有些违反直觉。你是说每个boxer 有一个title,但每个title 可能有多个boxers,对吗?在这种情况下,虽然直觉上我们会讨论属于拳击手的头衔,但您的关联实际上应该是相反的:每个头衔都有很多拳击手,每个拳击手都属于一个头衔。所以:

      # title
      has_many :boxers
      
      # boxer
      belongs_to :title
      

      如果您在 Rails 中有 has_onehas_many 关联,则另一方必须始终有 belongs_to,并且这应该在具有另一个表的 foreign_key 的模型上。综上所述,Rails 通常假定boxers 表有一个名为title_id 的列,它对应于titlesid 列中的值。鉴于您尚未这样做,您需要提供额外信息,以便 Rails 能够正确处理关联。

      具体来说,您需要告诉 Rails Boxer 模型使用 title 作为外键,并且这对应于 Title 的 name

      # title
      has_many :boxers, primary_key: :name, foreign_key: :title
      
      # boxer
      belongs_to :title, foreign_key: :title
      

      我建议改为使用更标准的设置,并删除拳击手上的 title 字段以支持 title_idRailsGuide on Active Record Associations 可能也值得一看,因为它有相当多的细节来说明这一切是如何运作的。

      【讨论】:

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