2011-04-03 35 views
2
create_table "friendships", :force => true do |t| 
    t.integer "user_id" 
    t.integer "friend_id" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    end 

    create_table "likes", :force => true do |t| 
    t.string "name" 
    t.integer "user_id" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    end 

    create_table "users", :force => true do |t| 
    t.string "name" 
    t.datetime "created_at" 
    t.datetime "updated_at" 
    end 

这些都是:has_many:通过不与会议名称关联?

class User < ActiveRecord::Base 

    has_many :friendships 
    has_many :friends, :through => :friendships 
    has_many :likes 
    has_many :friends_likes, :through => :friendships, :source => :likes 

end 

class Friendship < ActiveRecord::Base 

    belongs_to :user 
    belongs_to :friend, :class_name => "User", :foreign_key => "friend_id" 
    has_many :likes, :foreign_key => :user_id, 
end 

class Like < ActiveRecord::Base 

    belongs_to :user 
    belongs_to :friendship 

end 

我试图让“朋友喜欢”的模型,但我不能。

“User.find(1).friends_likes” 给出了SQL查询

SELECT "likes".* FROM "likes" INNER JOIN "friendships" ON "likes".user_id = "friendships".id WHERE (("friendships".user_id = 1)) 

但我认为必须是“INNER JOIN “友谊” ON “喜欢” .user_id = “友谊”。friend_id

我该怎么做? 感谢

回答

1

最简单的解决方案可能是在User模型,构建正确的SQL添加实例方法friends_likes

def likes_of_friends 
    friends.includes(:likes).map(&:likes) 
    end 

.includes(:likes)是性能,以避免N + 1查询的情况。

然后你User.find(1).friends_likes将产生如下疑问,假设用户1与IDS 2和3的朋友:

User Load (0.1ms) SELECT `users`.* FROM `users` LIMIT 1 
    User Load (0.4ms) SELECT `users`.* FROM `users` INNER JOIN `friendships` ON `users`.id = `friendships`.friend_id WHERE ((`friendships`.user_id = 1)) 
    Like Load (0.2ms) SELECT `likes`.* FROM `likes` WHERE (`likes`.user_id IN (2,3)) 

如果你真的需要在一个查询中的一切,你可以写直线上升的SQL:

Like.find_by_sql("select likes.* from 
    likes 
    inner join users as friends 
     on friends.id = likes.user_id 
    inner join friendships 
     on friendships.friend_id = friends.id 
    where friendships.users_id = 1; 
") 

不直截了当的原因是因为一个用户“拥有”了友谊 - 这是单向的,而且似乎没有办法获得与“朋友”相关的友谊(指定通过友谊桌上的friend_id E)。

所以,并称相反的方向将有助于(奇怪的命名除外):

class Friendships 
    # ... 
    has_many :befriendedships, :class_name => "Friendship", :foreign_key => "friend_id" 
end 

然后,您可以查询你更简单地找了一下的东西:

Like.joins(:user => :befriendedships).where(["friendships.user_id = ?", 1]) 

这将生成与find_by_sql示例基本相同的SQL。