如何在同一个Rails模型中使用两个记录作为不同Rails模型中的外键?

时间:2018-01-30 10:39:08

标签: ruby-on-rails ruby database model

我有两个模型:person.rb和relationship.rb

我需要my:relationships表来引用:people表中的两行作为外键。

以下是两个表的迁移:

class CreatePeople < ActiveRecord::Migration[5.1]
  def change
    create_table :people do |t|
      t.string :first_name
      t.string :second_name
      t.integer :age
      t.string :gender
      t.timestamps
    end
  end
end

class CreateRelationships < ActiveRecord::Migration[5.1]
  def change
    create_table :relationships do |t|
      t.references :person_a
      t.references :person_b
      t.string :status
      t.timestamps
    end
  end
end

这个想法是:person_a和:person_b字段都是来自:people表的个别记录,引用为外键,而:status字段只是对其关系的描述(“已婚”,“朋友”, “分开”等。)

我试图找出:

1)我必须在上面的CreateRelationships迁移中编写的附加代码是什么,以便将:person_a和:person_b up设置为:people表中的外键?

2)我需要在下面的两个表的模型文件(person.rb和relationship.rb)中编写什么代码来定义我正在谈论的关系结构?

class Person < ApplicationRecord
end

class Relationship < ApplicationRecord
end

我在这里发现另外一个问题来解决这个问题,但是给出的答案是冲突的,有些是不完整的,而其他人则使用旧版本的Rails。他们都没有为我工作。

我正在使用Rails 5.1.4

4 个答案:

答案 0 :(得分:3)

您已正确定义了迁移,只需在模型中添加以下内容即可定义模型之间的关系。

    class Person < ApplicationRecord::Base
      has_many :relationships, dependent: :destroy
    end

    class Relationship < ApplicationRecord::Base
      belongs_to :person_a, :class_name => 'Person'
      belongs_to :person_b, :class_name => 'Person'
    end

这允许您访问关系所属的Person,如下所示:

@relationship.person_a #user assigned as the first person.
@relationship.person_b #user assigned as the second person.

希望这有效。

答案 1 :(得分:1)

我必须为聊天模块做同样的事情,这是一个如何做到的例子:

class Conversations < ApplicationRecord
  belongs_to :sender, foreign_key: :sender_id, class_name: 'User'
  belongs_to :recipient, foreign_key: :recipient_id, class_name: 'User'
end

class User < ApplicationRecord
  ...
  has_many :conversations
  has_many :senders, through: :conversations, dependent: :destroy
  has_many :recipients, through: :conversations, dependent: :destroy
  ...
end

complex-has-many-through

的更多解释

希望它有所帮助,

答案 2 :(得分:1)

编辑:为匆忙和错误的答案道歉。

最初,我认为简单的has_many/belongs_to关联是可能和充分的。

class Person < ApplicationRecord
  has_many :relationships #dependent: :destroy
end

class Relationship < ApplicationRecord
  belongs_to :person_a, class_name: "Person"
  belongs_to :person_b, class_name: "Person"

  enum status: [:married, :friends, :separated]
end

正如@engineersmnky指出的那样,has_many关联无法在此处工作,因为person_id表中没有relationships列。由于我们只能在has_many关联中声明一个自定义外键,因此无法以这种方式声明它。 belongs_to会起作用,但我认为这还不够。

一种方法是跳过声明has_many并坚持使用自定义方法查询关系:

class Person < ApplicationRecord
  def relationships
    Relationship.where("person_a_id = ? OR person_b_id = ?", id, id)
  end
end

它会为您提供一个ActiveRecord::Relation,其中包含您需要的记录。这个解决方案的缺点很多 - 根据您的需要,您可能需要更多的代码来插入数据,从setter方法开始为人们分配关系......

什么是真正的解决方案,是在关系模型中使用复合主键 - 由:person_a_id:person_b_id组成。 ActiveRecord不支持复合主键,但this gem似乎填补了空白。显然它允许声明这样的密钥并将其用作has_many关联中的外键。问题是你的person_a / person_b对在relationships表中必须是唯一的。

答案 3 :(得分:0)

你可以这样做 在关系模型中写

belongs_to : xyz, class_name: "Person", foreign_key: "person_a"
belongs_to : abc, class_name: "Person", foreign_key: "person_b"

In Person模型写

has_many :relationships, dependent: :destroy
希望它会有所帮助