Ruby on rails-Referencia el mismo modelo dos veces?


¿Es posible establecer una doble relación en los modelos activerecord a través del comando generate scaffold?

Por ejemplo, si tuviera un modelo User y un modelo PrivateMessage, la tabla pm tendría que realizar un seguimiento de ambos sender y recipient.

Obviamente, para una sola relación simplemente haría esto:

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

¿Hay una forma similar de establecer dos relaciones?

También, ¿hay de todos modos para establecer alias para las relaciones?

Así que en lugar de diciendo:

@message.user

Puedes usar algo como:

@message.sender o @message.recipient

Cualquier consejo sería muy apreciado.

Gracias.

Author: aceofbassgreg, 2010-01-13

4 answers

Añada 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 ambas referencias al modelo User.

En lugar de user:references en tu comando generate necesitarías sender:references y recipient:references

 51
Author: Veger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-03 20:05:05

Aquí hay una respuesta completa a este problema, en caso de que las personas que visitan esta pregunta sean nuevas en Ruby on Rails y tengan dificultades para armar todo (como lo estaba cuando miré por primera vez en esto).

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í está especificando que hay dos columnas en esta tabla que se denominarán :sender y :recipient y que contienen referencias a otra tabla. Rails creará columnas llamadas 'sender_id' y 'recipient_id' para usted. En nuestro caso, cada fila de referencia en la tabla Users, 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 PrivateMessage llamada :sender, luego especificando que esta propiedad está relacionada con la clase User. Rails, al ver el "belongs_to: sender", buscará una columna en su base de datos llamada "sender_id", que definimos arriba, y utilícelo para almacenar la clave foránea. Entonces estás haciendo exactamente lo mismo para el destinatario.

Esto le permitirá acceder a su Remitente y Destinatario, ambas instancias del modelo User, a través de una instancia del modelo 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 User llamada: sent_private_messages, especificando que esta propiedad está relacionada con el Modelo PrivateMessage, y que la clave foránea en el modelo PrivateMessage que la relaciona con esta propiedad se llama 'sender_id'. Entonces usted está haciendo lo mismo para los mensajes privados recibidos.

Esto le permite obtener todos los mensajes privados enviados o recibidos de un usuario haciendo algo como esto:

@user.sent_private_messages
@user.received_private_messages

Al hacer cualquiera de estas opciones, se devolverá una matriz de instancias del modelo PrivateMessage.

....

 101
Author: Richard Jones,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-30 22:19:42

Hola para que ambas relaciones laterales hagan lo siguiente en sus 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...

 16
Author: radmehr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-23 12:43:59

Las respuestas anteriores, si bien son excelentes, no crean restricciones de clave foránea en la base de datos, sino que solo crean índices y columnas bigint. Para asegurarse de que se aplica la restricción de clave foránea, 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 las restricciones de clave externa en la base de datos que está utilizando.

 8
Author: bbengfort,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-13 01:50:57