Ruby on Rails: Mehrere has_many: durch möglich?
-
24-09-2019 - |
Frage
Ist es möglich, mehr has_many :through
Beziehungen zu haben, die in Schienen durcheinander passieren? Ich erhielt den Vorschlag, um eine Lösung für eine andere Frage zu tun, ich gepostet, aber nicht gelungen, sie zur Arbeit zu kommen.
Freunde sind eine zyklische Vereinigung durch einen Tisch kommen. Das Ziel ist es, eine has_many :through
für friends_comments
zu erstellen, so dass ich eine User
nehmen und etwas tun, wie user.friends_comments
alle Kommentare von seinen Freunden in einer einzigen Abfrage gemacht zu bekommen.
class User
has_many :friendships
has_many :friends,
:through => :friendships,
:conditions => "status = #{Friendship::FULL}"
has_many :comments
has_many :friends_comments, :through => :friends, :source => :comments
end
class Friendship < ActiveRecord::Base
belongs_to :user
belongs_to :friend, :class_name => "User", :foreign_key => "friend_id"
end
Das sieht gut aus und macht Sinn, ist aber nicht für mich arbeiten. Dies ist der Fehler ich in relevanten Teil bekommen, wenn ich versuche, eine friends_comments des Benutzers zuzugreifen:
ERROR: column users.user_id does not exist
: SELECT "comments".* FROM "comments" INNER JOIN "users" ON "comments".user_id = "users".id WHERE (("users".user_id = 1) AND ((status = 2)))
Wenn ich nur user.friends eingeben, die funktioniert, ist dies die Abfrage führt sie:
: SELECT "users".* FROM "users" INNER JOIN "friendships" ON "users".id = "friendships".friend_id WHERE (("friendships".user_id = 1) AND ((status = 2)))
So ist es, wie es scheint, über den ursprünglichen has_many
durch Freundschaft Beziehung völlig vergessen hat, und dann unangemessen versucht, die Benutzerklasse zu verwenden, wie eine Tabelle verbinden.
Bin ich etwas falsch zu machen, oder ist dies einfach nicht möglich?
Lösung
Edit:
Rails 3.1 unterstützt verschachtelte Verbände. Z. B:
has_many :tasks
has_many :assigments, :through => :tasks
has_many :users, :through => :assignments
Es besteht keine Notwendigkeit für die Lösung weiter unten. Siehe diese Screencasts für weitere Details.
Original Antwort
Sie passieren eine has_many :through
Vereinigung als Quelle für einen anderen has_many :through
Verband. Ich glaube nicht, es wird funktionieren.
has_many :friends,
:through => :friendships,
:conditions => "status = #{Friendship::FULL}"
has_many :friends_comments, :through => :friends, :source => :comments
Sie haben drei Ansätze, um dieses Problem zu lösen.
1) eine Assoziation Erweiterung
has_many :friends,
:through => :friendships,
:conditions => "status = #{Friendship::FULL}" do
def comments(reload=false)
@comments = nil if reload
@comments ||=Comment.find_all_by_user_id(map(&:id))
end
end
Jetzt können Sie die Freunde Kommentare erhalten wie folgt:
user.friends.comments
2) Fügen Sie eine Methode zur User
Klasse.
def friends_comments(reload=false)
@friends_comments = nil if reload
@friends_comments ||=Comment.find_all_by_user_id(self.friend_ids)
end
Jetzt können Sie die Freunde Kommentare erhalten wie folgt:
user.friends_comments
3) Wenn Sie wollen, dass diese dann noch effizienter sein:
def friends_comments(reload=false)
@friends_comments = nil if reload
@friends_comments ||=Comment.all(
:joins => "JOIN (SELECT friend_id AS user_id
FROM friendships
WHERE user_id = #{self.id}
) AS friends ON comments.user_id = friends.user_id")
end
Jetzt können Sie die Freunde Kommentare erhalten wie folgt:
user.friends_comments
Cache Alle Methoden, die Ergebnisse. Wenn Sie die Ergebnisse gehen Sie wie folgt neu geladen werden soll:
user.friends_comments(true)
user.friends.comments(true)
oder noch besser:
user.friends_comments(:reload)
user.friends.comments(:reload)
Andere Tipps
Es ist ein Plugin, das Ihr Problem löst, werfen Sie einen Blick auf Blog .
Sie installieren das Plugin mit
script/plugin install git://github.com/ianwhite/nested_has_many_through.git
Obwohl dies in der Vergangenheit nicht funktioniert hat, funktioniert es gut in Rails 3.1 jetzt.
ich diesen Blog-Eintrag gefunden, nützlich zu sein: http://geoff.evason.name/2010/04/23/nested-has_many-through-in-rails-or-how-to-do- a-3-table-Level /