Ich bin auf einen Fehler gestoßen, der im Material nicht erwähnt wurde, als ich ihn in das Rails-Tutorial aufgenommen habe. Untersuchen Sie die Ursache des Fehlers und fassen Sie die Lösung zusammen.
・ Rails-Tutorial https://railstutorial.jp/ ・ Rails Guide Association of Active Record https://railsguides.jp/association_basics.html ・ [Rails] So überprüfen Sie den Inhalt der Datenbank [Cloud9] https://shuheitakada.com/rails-database-check
Folgen Sie dem Rails Tutorial 6. Ausgabe ・ Verwenden Sie cloud9 ・ Ruby 2.6.3p62 ・ Schienen 6.0.3
Rails Tutorial Kapitel 14 14.3.3 Unterauswahl Übung 3 verursacht einen Fehler. Der Zweck dieser Übung besteht darin, die Joins-Methode zu verwenden, um die Mikroposts anzuzeigen, die den folgenden Benutzern und sich selbst als Feed zugeordnet sind. Es sieht auf den ersten Blick gut aus,
Wenn Sie einen Mikropost posten,
Es ist zu viel Freude, egal was passiert. Untersuchen Sie die Ursache, während Sie das Gefühl unterdrücken, nicht klar zu genießen.
Die Zuordnung jedes Modells ist wie folgt.
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
Die Struktur jeder Tabelle ist wie folgt.
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
Gehen Sie zunächst in die Konsole und überprüfen Sie die von Rails erstellten SQL-Anweisungen.
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;
Überprüfen Sie als Nächstes die Struktur und die Daten der Tabelle, die mit der Join-Methode in der Datenbankkonsole erstellt wurden.
rails_dbconsole
#Zeigen Sie den Spaltennamen im Ergebnis von SELECT an
>>.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;
#Suchergebnisse|~|Bedeutet, dass Spalten weggelassen werden
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|~|
Anscheinend verursacht follower_id eine Verdoppelung in Microposts. Übrigens, weil die Anzahl der Duplikate von Micropost und die Anzahl der eigenen Follower übereinstimmen, Es kann gefolgert werden, dass Follower die Ursache für die Duplizierung sind.
Mit anderen Worten, im Fall einer Folgebeziehung wie der folgenden ID: 1 Tanaka → ID: 2 Suzuki ID: 2 Suzuki → ID: 1 Tanaka ID: 3 Sato → ID: 1 Tanaka ID: 3 Sato → ID: 2 Suzuki Eine Tabelle wie die unten gezeigte wird erstellt. Mit Micopost.where werden der grüne Rahmen und der rote Rahmenteil extrahiert und der rote Rahmenteil verdoppelt.
models/user.rb
#Grüner Rahmenteil
relationships.follower_id = :id:
#Roter Rahmenteil
microposts.user_id = :id
Ich habe lange gebraucht, um die Ursache herauszufinden, aber sobald ich die Lösung herausgefunden hatte, konnte ich sie in nur einem Wort lösen.
Um einen eindeutigen Datensatz ohne Duplizierung zu erhalten, wird die "eindeutige" Methode verwendet.
Ich werde versuchen, es sofort zu integrieren.
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
OK!!
Jetzt ist die Zeit, einen Test zu schreiben. Testen Sie also, ob es keine doppelten Mikroposts gibt, die ich im Feed gepostet habe.
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
#Posten eines Mikroposts
content = "This micropost is only one!"
post microposts_path, params: { micropost: { content: content }}
follow_redirect!
#Bestätigung der Feed-Duplizierung
assert_select 'span.content', { :count=>1, :text=> "#{content}" }
end
#Copyright (c) 2016 Michael Hartl
Recommended Posts