59

activerecord是否可以通过命令在模型中建立双重关系generate scaffold

例如,如果我有一个User模型和一个PrivateMessage模型,private_messages 表需要同时跟踪senderrecipient

显然,对于单一的关系,我会这样做:

ruby script/generate scaffold pm title:string content:string user:references

有没有类似的方法来建立两个关系?

另外,有没有为关系设置别名?

所以与其说:

@message.user

你可以使用类似的东西:

@message.sender或者@message.recipient

任何建议将不胜感激。

谢谢。

4

4 回答 4

138

这是这个问题的完整答案,以防访问这个问题的人是 Ruby on Rails 的新手并且很难将所有东西放在一起(就像我第一次研究这个问题时一样)。

解决方案的某些部分发生在您的迁移中,一些发生在您的模型中:

迁移

class CreatePrivateMessages < ActiveRecord::Migration
  def change
    create_table :private_messages do |t|
      t.references :sender
      t.references :recipient
    end
    # Rails 5+ only: add foreign keys
    add_foreign_key :private_messages, :users, column: :sender_id, primary_key: :id
    add_foreign_key :private_messages, :users, column: :recipient_id, primary_key: :id
  end
end

在这里,您指定此表中有两列将被称为 :sender 和 :recipient ,它们包含对另一个表的引用。Rails 实际上会为您创建名为 'sender_id' 和 'recipient_id' 的列。在我们的例子中,它们将引用用户表中的每个行,但我们在模型中指定,而不是在迁移中。

楷模

class PrivateMessage < ActiveRecord::Base
  belongs_to :sender, :class_name => 'User'
  belongs_to :recipient, :class_name => 'User'
end

在这里,您将在 PrivateMessage 模型上创建一个名为 :sender 的属性,然后指定该属性与 User 类相关。Rails 看到“belongs_to :sender”,将在您的数据库中查找我们在上面定义的名为“sender_id”的列,并使用它来存储外键。然后你为收件人做同样的事情。

这将允许您通过 PrivateMessage 模型的实例访问您的发件人和收件人,这两个用户模型的实例,如下所示:

@private_message.sender.name
@private_message.recipient.email

这是您的用户模型:

class User < ActiveRecord::Base
  has_many :sent_private_messages, :class_name => 'PrivateMessage', :foreign_key => 'sender_id'
  has_many :received_private_messages, :class_name => 'PrivateMessage', :foreign_key => 'recipient_id'
end

在这里,您将在用户模型上创建一个名为 :sent_private_messages 的属性,指定此属性与 PrivateMessage 模型相关,并且将其与此属性相关的 PrivateMessage 模型上的外键称为“sender_id”。然后你对收到的私人消息做同样的事情。

这使您可以通过执行以下操作来获取所有用户发送或接收的私人消息:

@user.sent_private_messages
@user.received_private_messages

执行其中任何一个都将返回 PrivateMessage 模型的实例数组。

……

于 2012-04-21T15:42:55.153 回答
63

将此添加到您的模型中

belongs_to :sender, :class_name => "User"
belongs_to :recipient, :class_name => "User"

并且您可以调用@message.sender并且@message.recipient都引用 User 模型。

而不是user:references在您的生成命令中,您需要sender:referencesrecipient:references

于 2010-01-13T14:21:19.757 回答
18

您好,在您的两个模型中,双方的关系都如下所示:

class Message < ActiveRecord::Base

 belongs_to     :sender,
                :class_name => "User",
                :foreign_key  => "sender_id"

 belongs_to     :recipient,
                :class_name => "User",
                :foreign_key  => "recipient_id" 
end

class User < ActiveRecord::Base

  has_many      :sent, 
                :class_name => "Message",
                :foreign_key  => "sent_id"

  has_many      :received, 
                :class_name => "Message", 
                :foreign_key  => "received_id"
end

我希望这可以帮助你...

于 2011-05-23T12:43:59.893 回答
11

上面的答案虽然很好,但不会在数据库中创建外键约束,而是只创建索引和 bigint 列。要确保强制执行外键约束,请将以下内容添加到您的迁移中:

class CreatePrivateMessages < ActiveRecord::Migration[5.1]
    def change
        create_table :private_messages do |t|
          t.references :sender
          t.references :recipient
        end

        add_foreign_key :private_messages, :users, column: :sender_id, primary_key: :id
        add_foreign_key :private_messages, :users, column: :recipient_id, primary_key: :id
    end
end

这将确保在您使用的数据库中的sender_idrecipient_id以及外键约束上创建索引。

于 2017-09-13T01:50:57.693 回答