Ruby on rails - 两次引用相同的模型?

时间:2010-01-13 14:16:16

标签: ruby-on-rails rails-activerecord relationships

是否可以通过activerecord命令在generate scaffold模型中设置双重关系?

例如,如果我有User模型和PrivateMessage模型,则pm表需要跟踪senderrecipient

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

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

是否有类似的方式来建立两种关系?

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

所以不要说:

@message.user

您可以使用以下内容:

@message.sender@message.recipient

非常感谢任何建议。

感谢。

4 个答案:

答案 0 :(得分:113)

以下是这个问题的完整答案,如果访问此问题的人不熟悉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”的列。在我们的例子中,他们将每个引用Users表中的行,但我们在模型中指定,而不是在迁移中。

模型

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

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

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

@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模型的实例数组。

...

答案 1 :(得分:56)

将此添加到您的模型

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

您可以致电@message.sender@message.recipient,并且都引用用户模型。

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

答案 2 :(得分:17)

你好 在两个模型中都有两个侧面关系:

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

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

答案 3 :(得分:8)

上述答案虽然很好,但不会在数据库中创建外键约束,而只会创建索引和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上创建索引以及您正在使用的数据库中的外键约束。