2

Я хочу (в качестве примера) создать ассоциацию has_many для всех сообщений от друзей человека, что-то вроде has_many :remote_posts, чтобы дать мне что-то вроде person > friends > person > posts.has_many via self referential association

..здесь как бы я идти о нем

script/generate model post title:string person_id:integer 
script/generate model friendship person_id:integer friend_id:integer 
script/generate model person name:string 

class Person < ActiveRecord::Base 
    has_many :posts 
    has_many :friendships, :foreign_key => 'friend_id' 
    has_many :people, :through => :friendships 
    has_many :remote_posts, :class_name => 'Post', :through => :people, :source => :posts 
end 
class Friendship < ActiveRecord::Base 
    belongs_to :person 
    #also has a 'friend_id' to see who the friendship is aimed at 
end 
class Post < ActiveRecord::Base 
    belongs_to :person 
end 

# generate some people and friends 
{'frank' => ['bob','phil'], 'bob' => ['phil']}.each {|k,v| 
    v.each {|f| 
    Friendship.create(
     :person_id => Person.find_or_create_by_name(f).id, 
     :friend_id => Person.find_or_create_by_name(k).id 
    ) 
    } 
} 
# generate some posts 
Person.all.each {|p| 
    p.posts.create({:title => "Post by #{p.name}"}) 
} 

Теперь,

Person.first.friendships # ..works 
Person.first.people # (friends) ..works 
Person.first.posts # ..works 
Person.first.remote_posts #.... 

... и я получаю эту ошибку ..

ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: people.person_id: SELECT "posts".* FROM "posts" INNER JOIN "people" ON "posts".person_id = "people".id WHERE (("people".person_id = 1))

Помимо ошибки внешнего ключа - кажется, что дружба ассоциация не приходит в игру на всех. Я думал, что это может быть из-за :source => :posts, так как ассоциация posts входила в нее дважды.

Я мог бы написать какой-нибудь поисковый sql (и это то, что я сейчас работаю), хотя я бы скорее сделал это таким образом.

Любые идеи о том, как заставить это работать?

ответ

1

Как об этом:

В FriendShip классе, добавьте:

has_many :posts, :through => :person 


и в Person класса, измените remote_posts на:

has_many :remote_posts, :class_name => 'Post', 
     :through => :friendships, :source => :person 
+0

JRL, Это лучше! К сожалению, до сих пор не работает полностью (возможно, из-за несвязанной проблемы) , когда вы звоните:. Person.find_by_name («откровенное») remote_posts ..Это пожаров с этого SQL: SELECT «сообщения» . * FROM "сообщения" INNER JOIN "дружба" ON "сообщения" .id = "friendships" .person_id WHERE (("friendships" .friend_id = 2)) Он должен был присоединиться к posts.person_id вместо posts.id (так что он возвращает сообщения с тем же идентификатором, что и ваши друзья) Я попытался вставить некоторые: foreign_key, но, похоже, не работает. Спасибо за ваш ответ! – 2009-10-20 18:18:57

+0

Damnit - Я должен был знать, что он не будет правильно отформатировать. Проблема в том, что человек # remote_posts использует post.id вместо post.person_id - но я думаю, что там 80%! – 2009-10-20 18:21:43

0

Как насчет вложенное has_many :through отношений. Это, кажется, работает для меня:

class Friendship < ActiveRecord::Base 
    belongs_to :person 
    belongs_to :friend, :class_name => 'Person' 
    has_many :posts, :through => :friend, :source => :posts 
end 
class Person < ActiveRecord::Base 
    has_many :posts 
    has_many :friendships, :foreign_key => 'friend_id' 
    has_many :people, :through => :friendships 
    has_many :remote_posts, :through => :friendships, :source => :posts 
end 

Примечание: это требует это nested_has_many_through plugin. (Примечание: прямая связь с репозиториями github кажется сломанной ... но это репо есть, несмотря на сообщение об ошибке.)

Смежные вопросы