2010-07-09 20 views
13

Uso de rubí en los carriles, ¿cómo puedo lograr un polimórfica has_many relación en la que el propietario es siempre de un conocidos, pero los elementos de la asociación será de alguna polimórfico (pero homogénea) tipo, especificada por una columna de la ¿propietario? Por ejemplo, supongamos que los productos de la clase Producerhas_many pero las instancias del productor en realidad pueden tener muchas bicicletas, paletas heladas o cordones de zapatos. Puedo hacer que cada clase de producto (bicicleta, paletas, etc.) tenga una relación belongs_to con un productor, pero dado un ejemplo de productor, ¿cómo puedo obtener la colección de productos si son de diferentes tipos (por instancia de productor)?Rails has_many polimórfica

Las asociaciones polimórficas de Rails permiten a los productores pertenecer a muchos productos, pero necesito que la relación sea al revés. Por ejemplo:

class Bicycle < ActiveRecord::Base 
    belongs_to :producer 
end 

class Popsicle < ActiveRecord::Base 
    belongs_to :producer 
end 

class Producer < ActiveRecord::Base 
    has_many :products, :polymorphic_column => :type # last part is made-up... 
end 

Así que mi mesa Productor ya tiene una columna "tipo" que se corresponde con alguna clase de producto (por ejemplo, bicicletas, paleta, etc.), pero ¿cómo puedo obtener rieles que me deje hacer algo como:

>> bike_producer.products 
#=> [[email protected], [email protected], ...] 
>> popsicle_producer.products 
#=> [[email protected], [email protected], ...] 

Disculpe si esto es obvio o una repetición común; Estoy teniendo dificultades sorprendentes para lograrlo fácilmente.

+0

Así como una nota, recomiendo fuertemente en contra del uso de la fábrica como un nombre de modelo, como factory_girl es una extensión muy comúnmente usado usado para la generación de modelos en vez de accesorios, y esto puede ser muy confuso para la gente que lee el código. –

+0

@jamie - gracias por la sugerencia, cambié la terminología a "Productor", que ojalá no se confunda con ninguna biblioteca de concurrencia =) – maerics

+0

No hay problema. Además, no he encontrado una buena solución para esto. Hasta donde yo sé, la capacidad de un objeto para tener hijos polimórficos aún no existe en Rails. Si desea consultar http://blog.hasmanythrough.com/2006/4/3/polymorphic-through como referencia. –

Respuesta

1

Aquí está la solución que estoy usando actualmente. No proporciona cualquiera de los métodos de conveniencia (operaciones de recolección) que se obtienen de reales ActiveRecord :: Asociaciones, pero proporciona una manera de conseguir la lista de productos para un determinado productor:

class Bicycle < ActiveRecord::Base 
    belongs_to :producer 
end 

class Popsicle < ActiveRecord::Base 
    belongs_to :producer 
end 

class Producer < ActiveRecord::Base 
    PRODUCT_TYPE_MAPPING = { 
    'bicycle' => Bicycle, 
    'popsicle' => Popsicle 
    }.freeze 
    def products 
    klass = PRODUCT_TYPE_MAPPING[self.type] 
    klass ? klass.find_all_by_producer_id(self.id) : [] 
    end 
end 

Otra desventaja es que debo mantener el mapeo de cadenas de tipos para escribir clases, pero eso podría ser automático. Sin embargo, esta solución será suficiente para mis propósitos.

-1
class Note < ActiveRecord::Base 

belongs_to :note_obj, :polymorphic => true 
belongs_to :user 


end 


class Contact < ActiveRecord::Base 

belongs_to :contact_obj, :polymorphic => true 
belongs_to :phone_type 

end 



class CarrierHq < ActiveRecord::Base 


has_many :contacts, :as => :contact_obj 
has_many :notes, :as => :note_obj 


end 
+0

¿Puede explicar su respuesta un poco, quizás incluso modificarla para usar la terminología del productor/producto de la pregunta? – maerics

+0

clase de bicicletas true extremo clase Popsicle true extremo clase Productor : bicycle_obj has_many: Popsicle,: as =>: popsicle_obj final Utilice este código si usted tiene cualquier problema con el uso de objeto, entonces por favor deje un comentario en esta con el código. – user386660

1

por favor tome en formato

class Bicycle < ActiveRecord::Base 
    belongs_to :bicycle_obj,:polymorphic => true 
end 

class Popsicle < ActiveRecord::Base 
    belongs_to :popsicle_obj , :polymorphic => true 
end 

class Producer < ActiveRecord::Base 
    has_many :bicycles , :as=>:bicycle_obj 
    has_many :popsicle , :as=>:popsicle_obj 
end 

Usar este código. Si tiene algún problema, deje un comentario.

+0

Espera, ¿por qué publicaste dos respuestas? –

+0

mi respuesta comentada no estaba en el formato correcto, por eso doy una respuesta separada. – user386660

+0

Gracias @Jamie Wong: para revisiones en realidad soy el nuevo tipo de stackoverflow y no sé sobre el formato de texto – user386660

0

Encuentro que las asociaciones polimórficas están documentadas en Rails. Hay un esquema de herencia de tabla única, que es el que obtiene la mayor cantidad de documentación, , pero si no está utilizando la herencia de tabla única, entonces hay información faltante.

La asociación belongs_to se puede habilitar utilizando la opción: polymorphic => true. Sin embargo, a menos que esté usando una herencia de tabla única, la asociación has_many no funciona, ya que necesitaría conocer el conjunto de tablas que podrían tener una clave externa.

(Según lo que encontré), creo que la solución limpia es tener una tabla y un modelo para la clase base, y tener la clave externa en la tabla base.

create_table "products", :force => true do |table| 
    table.integer "derived_product_id" 
    table.string "derived_product_type" 
    table.integer "producer_id" 
    end 

    class Product < ActiveRecord::Base 
    belongs_to :producer 
    end 

    class Producer < ActiveRecord::Base 
    has_many :products 
    end 

Entonces, para un objeto de producción, productor, usted debe obtener los productos con producer.products.derived_products.

Todavía no he jugado con has_many para condensar la asociación con producer.derived_products, por lo que no puedo hacer ningún comentario sobre cómo hacerlo funcionar.

6

Tienes que usar STI en los productores, no en los productos. De esta manera, tiene un comportamiento diferente para cada tipo de productor, pero en una sola tabla producers.

(casi) ¡Sin polimorfismo en absoluto!

class Product < ActiveRecord::Base 
    # does not have a 'type' column, so there is no STI here, 
    # it is like an abstract superclass. 
    belongs_to :producer 
end 

class Bicycle < Product 
end 

class Popsicle < Product 
end 

class Producer < ActiveRecord::Base 
    # it has a 'type' column so we have STI here!! 
end 

class BicycleProducer < Producer 
    has_many :products, :class_name => "Bicycle", :inverse_of => :producer 
end 

class PopsicleProducer < Producer 
    has_many :products, :class_name => "Popsicle", :inverse_of => :producer 
end 
+0

¿Tener los productos heredados de la misma clase primaria afecta su variabilidad? Por ejemplo, ¿podría Bicycle tener un atributo "frame_material" y Popsicle tener un "sabor"? – maerics

+0

@maerics No hay ITS, todos los atributos provienen de cada una de las tablas específicas para las subclases. – rewritten

Cuestiones relacionadas