Ruby on Rails - ссылаться на одну и ту же модель дважды?
-
20-09-2019 - |
Вопрос
Можно ли установить двойные отношения в 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
Любой совет был бы очень признателен.
Спасибо.
Решение
Добавьте это в свою модель
has_one :sender, :class_name => "User"
has_one :recipient, :class_name => "User"
И вы можете позвонить @message.sender
а также @message.recipient
и оба ссылка на модель пользователя.
Вместо user:references
В вашей команде Generate вам понадобится sender:references
а также recipient:references
Другие советы
Вот полный ответ на этот вопрос, если люди, посещающие этот вопрос, являются новыми в Ruby на 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». В нашем случае каждый из них будет ссылаться на строки в таблице пользователей, но мы указываем это в моделях, а не в миграциях.
Модели
class PrivateMessage < ActiveRecord::Base
belongs_to :sender, :class_name => 'User'
belongs_to :recipient, :class_name => 'User'
end
Здесь вы создаете свойство в модели PrivateMessage с именем: отправитель, а затем указываете, что это свойство связано с пользовательским классом. Rails, увидев «принадлежности_TO: отправитель», будет искать столбец в вашей базе данных под названием «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.
....
Привет, чтобы оба побочных отношения сделали, как реже в ваших моделях:
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
Надеюсь, это вам поможет ...
Приведенные выше ответы, хотя и отличные, не создают ограничения иностранного ключа в базе данных, вместо этого создавая только индексы и столбцы 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
а также ограничения внешнего ключа в базе данных, которую вы используете.