Самое простое решение, вероятно, заключается в добавлении метода экземпляра friends_likes
в модель User
, которая создает правильный SQL:
def likes_of_friends
friends.includes(:likes).map(&:likes)
end
.includes(:likes)
для повышения производительности, чтобы избежать ситуации с запросом N + 1.
Тогда ваш User.find(1).friends_likes
выдаст следующие запросы, предполагая, что у пользователя 1 есть друзья с идентификаторами 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
на столе дружбы).
Итак, добавление противоположного направления поможет (странное название в стороне):
class Friendships
# ...
has_many :befriendedships, :class_name => "Friendship", :foreign_key => "friend_id"
end
Затем вы можете запросить что-то, что ищете немного проще:
Like.joins(:user => :befriendedships).where(["friendships.user_id = ?", 1])
Это сгенерирует по существу тот же SQL, что и пример find_by_sql
.