PERF: Don't load all poll_votes for a poll

This commit is contained in:
Daniel Waterworth 2020-09-05 16:14:45 +01:00
parent 13c9d7e704
commit f2842490d3
3 changed files with 16 additions and 16 deletions

View File

@ -55,7 +55,7 @@ class Poll < ActiveRecord::Base
end end
def has_voted?(user) def has_voted?(user)
user&.id && poll_votes.any? { |v| v.user_id == user.id } user&.id && poll_votes.where(user_id: user.id).exists?
end end
def can_see_voters?(user) def can_see_voters?(user)

View File

@ -45,7 +45,7 @@ class PollSerializer < ApplicationSerializer
end end
def voters def voters
object.poll_votes.map { |v| v.user_id }.uniq.count + object.anonymous_voters.to_i object.poll_votes.count('DISTINCT user_id') + object.anonymous_voters.to_i
end end
def close def close

View File

@ -68,7 +68,7 @@ after_initialize do
raise StandardError.new I18n.t("poll.user_cant_post_in_topic") raise StandardError.new I18n.t("poll.user_cant_post_in_topic")
end end
poll = Poll.includes(poll_options: :poll_votes).find_by(post_id: post_id, name: poll_name) poll = Poll.includes(:poll_options).find_by(post_id: post_id, name: poll_name)
raise StandardError.new I18n.t("poll.no_poll_with_this_name", name: poll_name) unless poll raise StandardError.new I18n.t("poll.no_poll_with_this_name", name: poll_name) unless poll
raise StandardError.new I18n.t("poll.poll_must_be_open_to_vote") if poll.is_closed? raise StandardError.new I18n.t("poll.poll_must_be_open_to_vote") if poll.is_closed?
@ -91,18 +91,18 @@ after_initialize do
obj << option.id if options.include?(option.digest) obj << option.id if options.include?(option.digest)
end end
old_option_ids = poll.poll_options.each_with_object([]) do |option, obj|
if option.poll_votes.where(user_id: user.id).exists?
obj << option.id
end
end
# remove non-selected votes # remove non-selected votes
PollVote PollVote
.where(poll: poll, user: user) .where(poll: poll, user: user)
.where.not(poll_option_id: new_option_ids) .where.not(poll_option_id: new_option_ids)
.delete_all .delete_all
old_option_ids = poll.poll_options.each_with_object([]) do |option, obj|
if option.poll_votes.any? { |v| v.user_id == user.id }
obj << option.id
end
end
# create missing votes # create missing votes
(new_option_ids - old_option_ids).each do |option_id| (new_option_ids - old_option_ids).each do |option_id|
PollVote.create!(poll: poll, user: user, poll_option_id: option_id) PollVote.create!(poll: poll, user: user, poll_option_id: option_id)
@ -575,7 +575,6 @@ after_initialize do
if post_with_polls.present? if post_with_polls.present?
Poll Poll
.includes(poll_options: :poll_votes, poll_votes: :poll_option)
.where(post_id: post_with_polls) .where(post_id: post_with_polls)
.each do |p| .each do |p|
polls[p.post_id] ||= [] polls[p.post_id] ||= []
@ -591,7 +590,7 @@ after_initialize do
@preloaded_polls ||= if @topic_view.present? @preloaded_polls ||= if @topic_view.present?
@topic_view.polls[object.id] @topic_view.polls[object.id]
else else
Poll.includes(poll_options: :poll_votes).where(post: object) Poll.includes(:poll_options).where(post: object)
end end
end end
@ -609,11 +608,12 @@ after_initialize do
add_to_serializer(:post, :polls_votes, false) do add_to_serializer(:post, :polls_votes, false) do
preloaded_polls.map do |poll| preloaded_polls.map do |poll|
user_poll_votes = poll.poll_votes.each_with_object([]) do |vote, obj| user_poll_votes =
if vote.user_id == scope.user.id poll
obj << vote.poll_option.digest .poll_votes
end .where(user_id: scope.user.id)
end .joins(:poll_option)
.pluck("poll_options.digest")
[poll.name, user_poll_votes] [poll.name, user_poll_votes]
end.to_h end.to_h