J'ai une association qui a besoin de quelques jointures / requêtes personnalisées. Lorsque vous essayez de déterminer comment implémenter cela, la réponse répétée est ArgumentError: Touche inconnue :: Finder_SQL P>
blockQuote> Ma requête pour faire la jointure ressemble à ceci: p> Je comprends que cela peut être atteint via: P> Finder_SQL CODE>. Cependant, dans Rails 4.2 (et plus):
has_many :tags, -> (user) {
select('DISTINCT "tags".*')
.joins('JOIN "articles_tags" ON "articles_tags"."tag_id" = "tags"."id"')
.joins('JOIN "articles" ON "article_tags"."article_id" = "articles"."id"')
.where('"articles"."user_id" = ?', user.id)
}, class_name: "Tag"
6 Réponses :
Donc, mon hypothèse est que vous obtenez l'erreur lorsque vous essayez d'accéder à Je pense donc que ce qui se passe est quand nous essayons d'accéder à l'utilisateur Bien sûr, ma réponse peut ne pas l'expliquer à 100%. N'hésitez pas à commenter votre pensée ou si vous trouvez quelque chose de mal, faites le moi savoir. p> @ user.tags code> puisque vous avez cette association à l'intérieur du
user.rb code>. p>.
@ user.tags code>, nous essayons d'extraire les balises
code> de l'utilisateur et à ce rails recherchera
Tags CODE> dont
user_id code> correspond à l'ID d'utilisateur actuellement fourni. Puisque les rails prennent le nom de l'association sous forme
modelname_id code> Format par défaut, même si vous n'avez pas
user_id code> Il tentera de rechercher dans cette colonne et de rechercher (ou d'ajouter
Où "tags". "User_id" code>), que vous le souhaitez ou non depuis l'objectif ultime, c'est de trouver des balises code> qui appartiennent à l'utilisateur actuel. P>
C'est correct - j'utilise user.tags code>. Aussi correct que la sortie correspond à ce que vous avez dit. Avez-vous une réponse que vous pensez résoudre? Je cherche vraiment un remplacement pour le
Finder_sql code> (avec
Finder_SQL code> Ceci peut être effectué). Merci.
OK, si je comprends bien cela correctement, je pense que j'ai la solution, qui utilise simplement les utilitaires Core Aciverecord et n'utilise pas Finder_SQL. P> pourrait potentiellement utiliser: p> ou alternativement, dans le modèle utilisateur modifie les balises HAS_MANY à P> Tag Load (0.4ms) SELECT DISTINCT `tags`.* FROM `tags` INNER JOIN `articles_tags` ON `tags`.`id` = `articles_tags`.`tag_id` INNER JOIN `articles` ON `articles_tags`.`article_id` = `articles`.`id` WHERE `articles`.`user_id` = 3
=> #<ActiveRecord::AssociationRelation [#<Tag id: 3, name: "tag 3", created_at: "2016-10-18 22:00:52", updated_at: "2016-10-18 22:00:52">, #<Tag id: 4, name: "tag 4", created_at: "2016-10-18 22:00:52", updated_at: "2016-10-18 22:00:52">, #<Tag id: 5, name: "tag 5", created_at: "2016-10-18 22:00:52", updated_at: "2016-10-18 22:00:52">, #<Tag id: 6, name: "tag 6", created_at: "2016-10-18 22:00:52", updated_at: "2016-10-18 22:00:52">, #<Tag id: 7, name: "tag 7", created_at: "2016-10-18 22:00:52", updated_at: "2016-10-18 22:00:52">]>
Essayez user.ProLoad (: tags) .ach {| utilisateur | met user.tags.inspect} code> et vous verrez les mauvaises requêtes de cardinalité.
Vous ne pensez pas que cela corrige le problème - voyez-vous le massif massif si vous exécutez l'extrait collé ci-dessus?
ah tu viens de déplacer les butballs xd .. j'aurai un look rapide
Oui, désolé n'a pas réalisé que cela n'allait pas clairement. Je cherche un remplacement / équivalence pour Finder_SQL code> qui fonctionne dans plusieurs cas - et les requêtes originales ont montré ce que je vois.
Le plus proche que je reçois, c'est utiliser has_many: tags, -> {distinct}, à travers :: articles
Bien que cela ne corrige pas votre problème directement - si vous n'avez besoin que d'un sous-ensemble de vos données, vous pouvez potentiellement le précharger via un sous-sélection:
CREATE OR REPLACE VIEW tags_users AS ( SELECT "users"."id" AS "user_id", "tags"."id" AS "tag_id" FROM "users" JOIN "articles" ON "users"."id" = "articles"."user_id" JOIN "articles_tags" ON "articles"."id" = "articles_tags"."article_id" JOIN "tags" ON "articles_tags"."tag_id" = "tags"."id" GROUP BY "user_id", "tag_id" )
La vue semble fonctionner (bien qu'elle soit réadonnée - mais cela a du sens). Il ne vidose pas mon schéma (probablement une question distincte) et on ne semble rien changer (mais cela soulève une exception lors de la tentative d'attribution). Cela pourrait être le meilleur effort (bien qu'un peu ennuyeux nécessitant une vue).
Peut être utile d'utiliser Ever_load " pour forcer Activerecord Exécutez des jointures. Ça fonctionne comme Voici un code de code: p> où Ce code va toucher une base de données au moins deux fois: p> Sélectionnez * à partir de l'article_Tags où l'article_id in (1,2,3 ...) - Beaucoup P>
blockQuote> p> inclut (: balises) .References (: balises) code>
l 'utilisateurs code> est une relation activeCord. p>
Vous êtes sur le bon chemin avec mais vous devez le faire: p> ou ceci: p> Quand je fais que je reçois cette requête: p> mais cela va toujours envoyer beaucoup de choses redondantes de la base de données à votre application. Cela sera plus rapide: p> donnant: p> faire juste has_many: tags, via :: Articles CODE> (ou même mieux
has_many: tags, -> {distinct}, via :: articles code> Comme Kevin le suggère). Mais vous devriez lire un peu sur Inclut VS Preload vs Ever_load . Vous faites ceci:
user.first.tags.map & : Nom code> me rejoint aussi: P>
SELECT DISTINCT "tags".*
FROM "tags"
INNER JOIN "articles_tags"
ON "tags"."id" = "articles_tags"."tag_id"
INNER JOIN "articles"
ON "articles_tags"."article_id" = "articles"."id"
WHERE "articles"."user_id" = ?
Il existe trois solutions possibles:
1) Continuez à utiliser faux 2) ajoutez une méthode d'instance sur la classe d'utilisateur p> si vous utilisez des balises code> pour les requêtes seulement et vous Je ne l'ai pas utilisé dans des jointures, vous pouvez utiliser cette approche: p> maintenant 3) OTOH, en utilisant has_many code> associations p>
user_id code> en l'ajoutant aux colonnes sélectionnées . p>
user.tags code> se comporte comme une association à des fins pratiques. p>
existe code> pourrait être performant que d'utiliser des P> distincts
class User < ActiveRecord::Base
def tags
exists_sql = %Q{
SELECT 1
FROM articles,
articles_tags
WHERE "articles"."user_id" = #{id} AND
"articles_tags"."article_id" = "article"."id" AND
"articles_tags"."tag_id" = "tags.id"
}
Tag.where(%Q{ EXISTS ( #{exists_sql} ) })
end
end
Où écrivez-vous ce
has_many: tags, -> (utilisateur) ... code>? Dans user.rb?
@sajan correct - dans
user.rb code>.