0

J'ai la structure suivante créée en ActiveRecord dans Rails 3Rails: INNER JOIN avec actes-as-tagable-sur les find_related_tags de donne erreur mysql

class Domain < AR 
    has_and_belongs_to_many :videos 
end 

class Video < AR 
    has_and_belongs_to_many :domains 
    acts_as_taggable_on :tags 
    scope :with_state, lambda { |s| where('state = ?', s) } 
end 

Quelque part dans mon contrôleur Je veux trouver d'autres vidéos à partir d'une vidéo basée sur un certain tag, ce qui est assez facile en utilisant la méthode find_related_tags. Mais je dois limiter les vidéos liées au domaine actuel qui est présent à travers une méthode d'assistance appelée current_domain, alors je suis venu avec la requête AR suivante:

@video = Video.find(params[:id]) 
@video.find_related_tags.joins(:domains).with_state(:converted).where('domains.id = ?', current_domain.id) 

Cette requête AR produit la requête MySQL suivante:

SELECT videos.*, COUNT(tags.id) AS count FROM videos, tags, taggings 
INNER JOIN `domains_videos` ON `domains_videos`.`video_id` = `videos`.`id` 
INNER JOIN `domains` ON `domains`.`id` = `domains_videos`.`domain_id` 
WHERE (videos.id != 5 AND videos.id = taggings.taggable_id 
    AND taggings.taggable_type = 'Video' 
    AND taggings.tag_id = tags.id 
    AND tags.name IN ('not')) 
    AND (state = 'converted') 
    AND (domains.id = 4) 
GROUP BY videos.id 
ORDER BY count DESC 

il semble bien pour moi, mais il produit une erreur MySQL:

Mysql2::Error: Unknown column 'videos.id' in 'on clause' 

Et que je ne comprends pas! Pourquoi videos.id est-il une colonne inconnue dans

INNER JOIN `domains_videos` ON `domains_videos`.`video_id` = `videos`.`id` 

Toutes les tables de jointure sont correctement configurées. Tout fonctionne. Si je supprime la partie .joins(:domains) cela fonctionne ... Je suis sûr que c'est quelque chose de simple que je ne vois juste pas :)

Répondre

0

Il semble que la requête MySQL est valide, mais la colonne videos.id est inconnue parce que les vidéos sont pas dans le jeu de jointures mais seulement utilisé dans la clause FROM. Donc, je me suis retrouvé avec la solution pour effectuer les opérations suivantes:

Video.find_by_sql(" 
    SELECT videos.*, COUNT(tags.id) AS count 
    FROM videos 
    INNER JOIN domains_videos ON domains_videos.video_id = videos.id 
    INNER JOIN domains ON domains.id = domains_videos.domain_id 
    INNER JOIN taggings ON videos.id = taggings.taggable_id AND taggings.taggable_type = '#{self.class.to_s}' 
    INNER JOIN tags ON taggings.tag_id = tags.id 
    WHERE tags.name IN (#{joined_tags}) 
    AND videos.state = 'converted' 
    AND domains.id = #{domain.id} 
    AND videos.id != #{id} 
    GROUP BY videos.id 
    ORDER BY count DESC 
    LIMIT #{limit} 
") 

Puisque tout est vraiment rejoint maintenant, la déclaration est maintenant valide pour MySQL.