7

Tengo tres clases: Persona, Posición y Directorio.Anular ActiveRecord << operador en has_many: a través de la relación, para aceptar datos para el modelo de unión

  • A Person has_many: directories,: through =>: position.
  • A Directorio has_muy: personas,: a través =>: posición.
  • Persona y directorio has_many: posiciones.
  • El modelo de posición, además de tener un id, un id_personal y un id_directorio, tiene uno o más campos adicionales (p. Ej., Título).

Lo que me gustaría hacer es agregar datos al modelo de unión, como el campo de título, cada vez que agrego una persona a una colección de Directory.people. El operador habitual < < no lo cortará. Id est:

directory = Directory.last  # Let's assume that retrieves a Directory object 
person = Person.last   # Let's assume that retrieves a Person object 
directory.people << person 

Esto añadirá una persona a la colección de la gente de un objeto de directorio, pero no me va a permitir la posibilidad de asignar los datos al modelo unirse. Así que, después de hacer un gran trabajo de investigación en este sitio, he encontrado otra manera de agregar a la persona a la colección de la gente y añadir datos a la posición que une la persona y el Directorio, id est:

directory = Directory.last  # Let's assume that retrieves a Directory object 
person = Person.last   # Let's assume that retrieves a Person object 
position = person.positions.build(:directory_id => directory.id, :title => "Administrative Assistant") 
position.save 

Este es incómodo. Una forma igualmente engorroso sería:

directory = Directory.last  # Let's assume that retrieves a Directory object 
person = Person.last   # Let's assume that retrieves a Person object 
position = Position.new(directory_id: directory.id, person_id: person.id, title: "Administrative Assistant") 

Una vez más, parece mal porque me gustaría ser capaz de hacer hincapié en la relación entre la persona y el Directorio, que creo que es lo que hace que el uso has_many: a través apropiado.

Lo que me gustaría ser capaz de hacer es usar el operador < <, y simplemente pasar los datos adicionales, por ejemplo:

directory = Directory.last # Let's assume that retrieves a Directory object 
person = Person.last # Let's assume that retrieves a Person object 
directory.people << person, :position => {:title => "Administrative Assistant"} 

he sobrecargado el operador < < en mi has_many: a través de la declaración , de la siguiente manera:

has_many :people, :through => :positions do 
    def << *args 
    arg = args.first 
    if arg.is_a?(Person) 
     self.push([arg]) 
    elsif arg.is_a?(Hash) 
     # Don't know what to do in here (see below) 
    else 
     raise "Invalid Value" # There's a better error to raise here, but good enough for now. 
    end 
    end 
end 

la ventaja de conseguir este trabajo es que funciona bien sintácticamente, y me permite asignar de forma concisa los datos en el objeto de unirse a (una posición) mientras se añade el Per hijo a la colección de personas del objeto Directorio.

Pero no puedo hacerlo funcionar porque necesitaría poder acceder al objeto de directorio del cual la colección de personas en el lado izquierdo del operador < < es un atributo, para construir una posición y guardarla en la base de datos.

Por lo tanto, mis preguntas son:

  1. ¿Hay una manera de acceder a un objeto desde un atributo de un objeto?
  2. Como alternativa, ¿hay alguna otra forma de sobrecargar el operador < < para que pueda asignar fácilmente datos al modelo de unión al agregar un objeto a una colección?

Muchas gracias por su ayuda y respuestas reflexivas. Estuve pirateando esto durante medio día sin ningún resultado.

respuesta Gracias a PinnyM, que respondió a esta pregunta, yo era capaz de llegar con esta aplicación:

module AddToPeopleAndPositionExtension 
    def << *args 
    arg = args.first 
     if arg.is_a?(Person) 
     self.push([arg]) 
     return self 
     elsif arg.is_a?(Hash) 
     directory = proxy_association.owner 
     person = arg[:person] 
     position = person.positions.build(:directory_id => directory.id, :title => arg[:position][:title]) 
     position.save 
     else 
     raise "Invalid Value" 
     end 
    end 
end 

class Directory < ActiveRecord::Base 
    # Relationships 
    has_many :positions 
    has_many :people, :through => :positions, :extend => AddToPeopleAndPositionExtension 
end 

Esto permitió que llame a la operadora < < en la forma estándar si lo hiciera no importa lo que sucede en el modelo de unirse, como:

directory = Directory.last  # Let's assume that retrieves a Directory object 
person = Person.last   # Let's assume that retrieves a Person object 
directory.people << person 

Y, yo también podría llamarlo de una manera que especifica los atributos del modelo de unirse como :

directory = Directory.last  # Let's assume that retrieves a Directory object 
person = Person.last   # Let's assume that retrieves a Person object 
directory.people << {:person => person, :position => {:title => "Administrative Assistant"}} 
+0

Lo he probado con rails 5.1 y no funciona por alguna razón. la función principal no se llama – dowi

Respuesta

11

Puede utilizar el ayudante proxy_association dentro del bloque para conseguir la asociación y proxy_association.owner para conseguir el mismo objeto del Directorio. Consulte here para obtener más información sobre esto.

+0

Gracias por su ayuda. Esto funciona. Actualizaré mi respuesta para reflejar la implementación completa, para cualquier otra persona que tenga este tipo de preguntas. –

Cuestiones relacionadas