2011-04-28 17 views
13

mi problema está siguiendo. ¿Cómo puedo une a belongs_to asociación de modelo polimórficoRails se une o precarga pertenece a la asociación del modelo polimórfico

Existe situación

opinion.rb

class Opinion < ActiveRecord::Base 
    belongs_to :opinionable, :polymorphic => true 
    belongs_to :category 
end 

answer.rb

class Answer < ActiveRecord::Base 
    has_many :opinions, :as => :opinionable 
end 

¿Cómo puedo hacer después de

Opinion.joins(:opinionabe).all

arrojará

ArgumentError: You can't create a polymorphic belongs_to join without specifying the polymorphic class!

¿Cómo puedo especificar a qué clase deseo unirme?

Segunda pregunta. Cómo precargarlo?

Opinion.preload(:opinionable).all

funciona bien. Hará una consulta para cada clase en belongs_to.

Pero. si quiero hacer algo como

Opinion.preload(:opinionable => :answer_form).all

hay un problema porque un modelo tiene esta asociación y el segundo no. Entonces arrojará una excepción.

Entonces, ¿cómo puedo hacer algo como

Opinion.preload(:answer => :answer_form, :another_belongs_to_model).all

?

Gracias, David!

Respuesta

13

Parece que no ha especificado la columna opinionable_type:string para su modelo de Opinión.

intenta actualizar la migración de esta manera:

class CreateOpinions < ActiveRecord::Migration 
    def self.up 
    create_table :opinions do |t| 
     t.integer :opinionable_id 
     t.string :opinionable_type 

     # ... other fields 

     t.timestamps 
    end 
    end 

    def self.down 
    drop_table :opinions 
    end 
end 

Esto va a resolver la segunda pregunta y Opinion.preload(:opinionable).all debería funcionar bien.

No se pueden realizar uniones en la asociación polimórfica porque pueden ubicarse en tablas diferentes, que se detectan después de que se carga el modelo Opinion. Por eso, el modelo necesita la columna opinionable_type.

Si intenta hacer esto obtendrá el próximo excepción

ActiveRecord::EagerLoadPolymorphicError : Can not eagerly load the polymorphic association :opinionable

UPD: Añadido magia unirse^_^

class Opinion < ActiveRecord::Base 
    belongs_to :opinionable, :polymorphic => true 

    belongs_to :opinionable_answer, :foreign_key => :opinionable_id, :class_name => "Answer" 

    scope :by_type, lambda { |type| joins("JOIN #{type.table_name} ON #{type.table_name}.id = #{Opinion.table_name}.opinionable_id AND #{Opinion.table_name}.opinionable_type = '#{type.to_s}'") } 
end 

Ejemplo:

Opinion.by_type(Answer).to_sql 
    => "SELECT \"opinions\".* FROM \"opinions\" JOIN answers ON answers.id = opinions.opinionable_id AND opinions.opinionable_type = 'Answer'" 
+0

Polyporhic funciona bien para mí (tener la columna ID y el tipo en la tabla). Tengo tu explicación de por qué no funciona. Eché de menos el hecho de que la modelo no sabe qué clases están en belongs_to. – Schovi

+0

Tener idea. Es posible algo así si conozco la clase Opinion.joins ([: opinionable, Answer])? – Schovi

+0

Si conoce la clase concreta, puede agregar algo como: 'belongs_to: opinionable_answer,: foreign_key =>: opinionable_id,: class_name =>" Answer "' into' Opinion' model. Y luego 'Opinion.joins (: opinionable_answer) 'debería funcionar bien. –

15

En realidad si solo haga

belongs_to :opinionable_answer, :foreign_key => :opinionable_id, :class_name => "Answer", conditions: { opinions: { opinionable_type: "Answer"}} 

entonces usted puede hacer

Opinion.joins(:opinionable_answer).where(answers: { awesome: true}) 
+0

¡Funcionó muy bien para mí! – Acco

+0

Gracias! Funciona como se esperaba :) – JCorcuera

Cuestiones relacionadas