[RUBY] [Rails] Obtenez un enregistrement unique de la table jointe par la méthode de jointure de Active Record (Tutoriel Rails Chapitre 14)

introduction

J'ai rencontré un bug qui n'était pas mentionné dans le matériel lors de son intégration dans le didacticiel Rails. Recherchez la cause du bogue et résumez la solution.

Ce que vous pouvez voir dans cet article

-Comment vérifier le nom de la colonne de la table jointe par la méthode "jointures" de Active Record -Comment utiliser la méthode "distincte" pour acquérir de manière unique des enregistrements en double

Matériel de référence

・ Tutoriel Rails  https://railstutorial.jp/ ・ Guide des rails Association of Active Record  https://railsguides.jp/association_basics.html ・ [Rails] Comment vérifier le contenu de la base de données [Cloud9]  https://shuheitakada.com/rails-database-check -Afficher le nom de la colonne comme en-tête lors de l'affichage du résultat de l'instruction SELECT (commande .headers)  https://www.dbonline.jp/sqlite/sqlite_command/index5.html ・ À propos de la méthode distincte de Rails  https://qiita.com/toda-axiaworks/items/ad5a0e2322ac6a2ea0f4

À propos de l'environnement

Suivez le didacticiel Rails 6e édition ・ Utilisez cloud9 ・ Rubis 2.6.3p62 ・ Rails 6.0.3

Motif d'apprentissage

Tutoriel Rails Chapitre 14 14.3.3 L'exercice de sous-sélection 3 provoque un bogue. Le but de l'exercice est d'utiliser la méthode des jointures pour afficher les micro-messages associés aux utilisateurs suivants et eux-mêmes sous forme de flux. Ça a l'air bien à première vue, image.png

Lorsque vous publiez un micro post, image.png

C'est trop de plaisir quoi qu'il arrive. Recherchez la cause tout en supprimant le sentiment de ne pas profiter clairement.

Association de modèles

L'association de chaque modèle est la suivante.

python


class User < ApplicationRecord
 has_many :microposts
 has_many :passive_relationships, class_name: "Relationship", foreign_key: "followed_id"      
 has_many :followers, through: :passive_relationships, source: :follower
end

class Relationship < ApplicationRecord
 belongs_to :follower, class_name: "User"
end

class Micropost < ApplicationRecord
 belongs_to :user
end

# Copyright (c) 2016 Michael Hartl

La structure de chaque table est la suivante. Rails Tutorial14章joinsの関連図.png

Le code qui l'a causé

models/user.rb


def feed
 part_of_feed = "relationships.follower_id = :id or microposts.user_id = :id"
 Micropost.joins(user: :followers).where(part_of_feed, { id: id })
end

# Copyright (c) 2016 Michael Hartl

Tout d'abord, allez dans la console et vérifiez les instructions SQL créées par Rails.

rails_console



>>user.feed

SELECT * FROM "microposts" INNER JOIN "users" ON "users"."id" = "microposts"."user_id" 
   INNER JOIN "relationships" ON "relationships"."followed_id" = "users"."id" 
   INNER JOIN "users" "followers_users" ON "followers_users"."id" = "relationships"."follower_id" 
   WHERE (relationships.follower_id = 1 or microposts.user_id = 1) 
   ORDER BY "microposts"."created_at" DESC;

Ensuite, vérifiez la structure et les données de la table créée par la méthode de jointure sur la console de base de données.

rails_dbconsole


#Afficher le nom de la colonne dans le résultat de SELECT
>>.header on

>>SELECT * FROM "microposts" INNER 
  JOIN "users" ON "users"."id" = "microposts"."user_id" 
  INNER JOIN "relationships" ON "relationships"."followed_id" = "users"."id" 
  INNER JOIN "users" "followers_users" ON "followers_users"."id" = "relationships"."follower_id" 
  WHERE (relationships.follower_id = 1 or microposts.user_id = 1) 
  ORDER BY "microposts"."created_at" DESC LIMIT 5;

#Résultats de recherche|~|Signifie omettre des colonnes
id|content|user_id|~|id|name|~|id|follower_id|followed_id|~|id|name|~|
308|Enjoy Coding !!|1|~|1|Example User|~|50|4|1|~|4|Mr. Rey Lemke|~|
308|Enjoy Coding !!|1|~|1|Example User|~|51|5|1|~|5|Dr. Louisa Price|~|
308|Enjoy Coding !!|1|~|1|Example User|~|52|6|1|~|6|Charisse Stamm|~|
308|Enjoy Coding !!|1|~|1|Example User|~|53|7|1|~|7|Sang Metz IV|~|
308|Enjoy Coding !!|1|~|1|Example User|~|54|8|1|~|8|Robt Hamill|~|

Apparemment, follower_id provoque une duplication dans Microposts. À propos, parce que le nombre de doublons de Micropost et le nombre de ses propres abonnés correspondent, On peut en déduire que les abonnés sont la cause de la duplication.

En d'autres termes, dans le cas d'une relation de suivi comme celle ci-dessous id: 1 Tanaka → id: 2 Suzuki id: 2 Suzuki → id: 1 Tanaka id: 3 Sato → id: 1 Tanaka id: 3 Sato → id: 2 Suzuki Un tableau comme celui illustré ci-dessous est créé. Par Micopost.where, le cadre vert et la partie cadre rouge sont extraits, et la partie cadre rouge est doublée. RailsTuorial14章Joinsで作成されるテーブルの模式図.png

models/user.rb


 #Partie de cadre vert
 relationships.follower_id = :id: 

 #Partie de cadre rouge
 microposts.user_id = :id

Solution

J'ai passé beaucoup de temps à essayer de comprendre la cause, mais une fois que j'ai trouvé la solution, je pouvais la résoudre en un seul mot.

Utilisez la méthode distincte

Afin d'obtenir des enregistrements uniques sans duplication, la méthode "distincte" sera utilisée.

J'essaierai de l'intégrer immédiatement.

models/user.rb


def feed
 part_of_feed = "relationships.follower_id = :id or microposts.user_id = :id"
 Micropost.joins(user: :followers).where(part_of_feed, { id: id }).distinct
end

#Copyright (c) 2016 Michael Hartl

image.png OK!!

Ecrire un test

Il est maintenant temps d'écrire un test. Donc, testez qu'il n'y a pas de micro-messages en double que j'ai publiés sur Feed.

test/integrationtest/microposts_interface_test.rb


 def setup
   @user = users(:michael)
 end 

 test "should feed have microposts with uniqueness" do
   log_in_as(@user)
   get root_path

   #Publier un micro post
   content = "This micropost is only one!"
   post microposts_path, params: { micropost: { content: content }}
   follow_redirect!

   #Confirmation de la duplication du flux
   assert_select 'span.content', { :count=>1, :text=> "#{content}" }
 end

#Copyright (c) 2016 Michael Hartl

Recommended Posts

[Rails] Obtenez un enregistrement unique de la table jointe par la méthode de jointure de Active Record (Tutoriel Rails Chapitre 14)
Comment créer une combinaison unique de données dans la table intermédiaire des rails
Une revue du code utilisé par les rails débutants
[Rails] Obtenons dynamiquement le seuil de validation du modèle "contrôle de longueur" à partir des informations de table
Un record d'étude du Spring Framework à partir de zéro
[Tutoriel Rails Chapitre 5] Créer une mise en page
Une série de flux de création de table → création, suppression d'enregistrement → suppression de table dans Ruby on Rails
Trouvez la différence à partir d'un multiple de 10
Décomposer l'installation de "$ printf": --no-document \ nupdate: --no-document \ n ">> ~ / .gemrc" dans le chapitre 1 du didacticiel Rails
Nommer et appeler explicitement des méthodes de classe parent dans Ruby
Obtenez le nom de classe et le nom de méthode du contrôleur exécuté par le HandlerInterceptor de Spring Boot