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?

War es hilfreich?

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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top