2011-04-28 6 views
13

mon problème est le suivant. Comment puis-je belongs_to association de se joint modèle polymorphesRails rejoint ou précharge appartient à l'association du modèle polymorphe

Il y a la situation

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 

Comment puis-je faire suivant

Opinion.joins(:opinionabe).all

il lancera

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

Comment puis-je précise quelle classe je veux rejoindre?

Deuxième question. Comment le précharger?

Opinion.preload(:opinionable).all

fonctionne très bien. Il fera une requête pour chaque classe dans belongs_to.

Mais. si je veux faire quelque chose comme

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

il y a un problème car un modèle a cette association et la seconde n'a pas. Donc, il va jeter l'exception.

Alors, comment je peux faire quelque chose comme

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

?

Merci, David!

Répondre

13

Il semble que vous n'avez pas spécifié la colonne opinionable_type:string pour votre modèle Opinion.

Essayez de mettre à jour votre migration de cette manière:

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 

Cela permettra de résoudre votre deuxième question et Opinion.preload(:opinionable).all devrait bien fonctionner.

Vous ne pouvez pas faire de jointures sur une association polymorphe car elles peuvent être situées dans différentes tables, qui sont détectées après le chargement du modèle Opinion. C'est pourquoi le modèle a besoin de la colonne opinionable_type.

Si vous essayez de le faire, vous aurez à côté exception

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

UPD: magie Ajouté rejoindre^_^

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 

Exemple:

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 fonctionne bien pour moi (et la colonne id ont le type dans le tableau). Vous avez votre explication pourquoi les jointures ne fonctionnent pas. J'ai manqué ce fait que le modèle ne sait pas quelles classes sont dans belongs_to. – Schovi

+0

Avoir une idée. Est-ce possible quelque chose comme ça f je connais la classe Opinion.joins ([: opinionable, Answer])? – Schovi

+0

Si vous connaissez la classe concrète, vous pouvez ajouter quelque chose comme: 'belongs_to: opinionable_answer,: foreign_key =>: opinionable_id,: class_name =>" Answer "' dans le modèle 'Opinion'. Et puis 'Opinion.joins (: opinionable_answer)' devrait fonctionner correctement. –

15

En fait, si vous faire

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

alors vous pouvez le faire

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

J'ai bien travaillé pour moi! – Acco

+0

Merci! Fonctionne comme prévu :) – JCorcuera

Questions connexes