#ruby-on-rails
#ruby-on-rails
Вопрос:
Я создаю копию Instagram. Я хочу сделать запрос, который даст мне всех пользователей, которым понравился пост. В итоге у пользователя столько сообщений, у публикации столько лайков, и у пользователя также много лайков. Это решения, которые я придумал
def get_user_likes
post = Post.find(params[:post_id])
#first solution
@user_likes = post.likes.map(amp;:users)
#second solution
@user_likes = User.includes(:likes).select(:username, :id, :profile_image).where(
likes: {post_id: params[:post_id])})
end
Я также хочу выбрать только несколько столбцов (в которых первый вариант мне не позволяет). С точки зрения производительности, какой из вариантов лучше? Есть ли лучший вариант?
Спасибо!!
Комментарии:
1. Первое решение вызовет запрос n 1, поскольку вы не включаете «пользователей». Второй вариант хорош, но если вы не будете использовать
Like
объекты, которые вы можете использоватьjoins
вместоincludes
, чтобы подобные объекты не загружались в память.
Ответ №1:
Как и в комментарии Мехмета, второе решение лучше. Я немного расширю комментарий, первое решение легко понять, но будет вызывать запрос для каждого подобного на карте, эти проблемы обычно известны как n 1 запросов.
Второе решение намного лучше, хотя и не совсем то, что вы хотите здесь. Includes выполнит второй запрос и будет полезен для итерации по объекту позже.
Лучшим решением является объединение, во-первых, потому что оно будет выполнять на один запрос меньше, а во-вторых, потому что вернет именно то, что вы, поэтому просто замените ваши включения на join, и все готово:
def user_likes
@user_likes = User.joins(:likes).select(:username, :id, :profile_image).where(likes: {post_id: params[:post_id])})
end
Я мог бы изучить больше, но ответом будет сообщение в блоге, и я могу порекомендовать сообщение в блоге для вас:
https://semaphoreci.com/blog/2017/08/09/faster-rails-eliminating-n-plus-one-queries.html