Рубин на рельсах - Ссылка на ту же модель дважды? - PullRequest
46 голосов
/ 13 января 2010

Можно ли установить двойное отношение в моделях activerecord с помощью команды generate scaffold?

Например, если бы у меня была модель User и модель PrivateMessage, таблица pm должна была бы отслеживать и sender, и recipient.

Очевидно, что для одного отношения я бы просто сделал это:

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

Есть ли подобный способ установить два отношения?

Кроме того, есть ли способ настроить псевдонимы для отношений?

Так что вместо того, чтобы сказать:

@message.user

Вы можете использовать что-то вроде:

@message.sender или @message.recipient

Любой совет будет принят с благодарностью.

Спасибо.

Ответы [ 4 ]

114 голосов
/ 21 апреля 2012

Вот полный ответ на этот вопрос, в случае, если люди, посещающие этот вопрос, являются новичками в 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

Здесь вы указываете, что в этой таблице есть два столбца, которые будут называться:отправитель и: получатель и которые содержат ссылки на другую таблицу.Rails фактически создаст для вас столбцы с именами 'sender_id' и 'receient_id'.В нашем случае они будут ссылаться на строки в таблице Users, но мы указываем это в моделях, а не в миграциях.

Models

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

Здесь вы создаете свойство дляМодель PrivateMessage с именем: sender, затем указывающая, что это свойство связано с классом User.Rails, увидев «own_to: sender», будет искать в вашей базе данных столбец с именем «sender_id», который мы определили выше, и использовать его для хранения внешнего ключа.Затем вы делаете то же самое для получателя.

Это позволит вам получить доступ к вашему Отправителю и Получателю, оба экземпляра модели User, через экземпляр модели 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.

....

56 голосов
/ 13 января 2010

Добавьте это к вашей модели

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

И вы можете звонить @message.sender и @message.recipient, и обе ссылки на модель пользователя.

Вместо user:references в вашей команде генерации вам понадобятся sender:references и recipient:references

17 голосов
/ 23 мая 2011

Привет, чтобы обе стороны делали то же, что и ниже, в обеих ваших моделях:

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

Надеюсь, это поможет вам ...

9 голосов
/ 13 сентября 2017

Приведенные выше ответы, хотя и превосходны, не создают ограничений внешнего ключа в базе данных, а только создают индексы и столбцы 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_id и recipient_id, а также ограничений внешнего ключа в используемой вами базе данных.

...