ruby-on-rails - has_one - rails model references
Ruby on rails: ¿hace referencia al mismo modelo dos veces? (4)
¿Es posible establecer una doble relación en los modelos activerecord
través del comando generate scaffold
?
Por ejemplo, si tuviera un modelo de User
y un modelo de PrivateMessage
, la tabla pm necesitaría hacer un seguimiento tanto del sender
como del recipient
.
Obviamente, para una relación única, simplemente haría esto:
ruby script/generate scaffold pm title:string content:string user:references
¿Hay alguna manera similar de establecer dos relaciones?
Además, ¿hay alguna forma de configurar alias para las relaciones?
Entonces, en lugar de decir:
@message.user
Puedes usar algo como:
@message.sender
o @message.recipient
Cualquier consejo sería muy apreciado.
Gracias.
Agregue esto a su modelo
has_one :sender, :class_name => "User"
has_one :recipient, :class_name => "User"
Y puede llamar a @message.sender
y @message.recipient
y a ambas referencias al modelo de Usuario.
En lugar de user:references
en tu comando de generación necesitarías sender:references
y recipient:references
Aquí hay una respuesta completa a este problema, en caso de que las personas que visiten esta pregunta sean nuevas en Ruby on Rails y tengan dificultades para unir todo (como yo lo hice cuando analicé esto por primera vez).
Algunas partes de la solución tienen lugar en sus Migraciones y algunas en sus Modelos:
Migraciones
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
Aquí especifica que hay dos columnas en esta tabla a las que se hará referencia como: remitente y destinatario y que contienen referencias a otra tabla. Rails en realidad creará columnas llamadas ''sender_id'' y ''recipient_id'' por usted. En nuestro caso, cada una de ellas hará referencia a las filas en la tabla Usuarios, pero lo especificamos en los modelos, no en las migraciones.
Modelos
class PrivateMessage < ActiveRecord::Base
belongs_to :sender, :class_name => ''User''
belongs_to :recipient, :class_name => ''User''
end
Aquí está creando una propiedad en el modelo de PrivateMessage llamado: sender, y luego especifica que esta propiedad está relacionada con la clase User. Rails, al ver "belongs_to: sender", buscará una columna en su base de datos llamada "sender_id", que definimos anteriormente, y la usará para almacenar la clave externa. Entonces estás haciendo exactamente lo mismo para el destinatario.
Esto le permitirá acceder a su remitente y destinatario, ambas instancias del modelo de usuario, a través de una instancia del modelo de PrivateMessage, como esta:
@private_message.sender.name
@private_message.recipient.email
Aquí está su Modelo de Usuario:
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
Aquí está creando una propiedad en el Modelo de usuario llamado: send_private_messages, especificando que esta propiedad está relacionada con el Modelo PrivateMessage, y que la clave externa en el modelo PrivateMessage que lo relaciona con esta propiedad se llama ''sender_id''. Entonces estás haciendo lo mismo con los mensajes privados recibidos.
Esto le permite obtener todos los usuarios enviados o recibidos mensajes privados haciendo algo como esto:
@user.sent_private_messages
@user.received_private_messages
Hacer cualquiera de estos devolverá una matriz de instancias del modelo de PrivateMessage.
....
Las respuestas anteriores, aunque son excelentes, no crean restricciones de clave externa en la base de datos, sino que solo crean índices y columnas bigint. Para garantizar el cumplimiento de la restricción de clave externa, agregue lo siguiente a su migración:
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
Esto asegurará que los índices se creen en sender_id
y recipient_id
, así como en las restricciones de clave externa en la base de datos que está utilizando.
hola para tener ambas relaciones secundarias haz lo siguiente en tus dos modelos:
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
Espero que esto te ayude...