Use subqueries to check reaction/subscription state
This commit is contained in:
parent
f91d2f2d7f
commit
b55e6da9a5
|
@ -8,15 +8,11 @@ class AnswerController < ApplicationController
|
||||||
turbo_stream_actions :pin, :unpin
|
turbo_stream_actions :pin, :unpin
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@answer = Answer.includes(question: [:user], smiles: [:user]).find(params[:id])
|
@answer = Answer.for_user(current_user).includes(question: [:user], smiles: [:user]).find(params[:id])
|
||||||
@display_all = true
|
@display_all = true
|
||||||
@reacted_answer_ids = []
|
|
||||||
@subscribed_answer_ids = []
|
|
||||||
|
|
||||||
return unless user_signed_in?
|
return unless user_signed_in?
|
||||||
|
|
||||||
@reacted_answer_ids = Reaction.where(user: current_user, parent: @answer).pluck(:parent_id)
|
|
||||||
@subscribed_answer_ids = Subscription.where(user: current_user, answer: @answer).pluck(:answer_id)
|
|
||||||
mark_notifications_as_read
|
mark_notifications_as_read
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,6 @@ module PaginatesAnswers
|
||||||
@answers = yield(last_id: params[:last_id])
|
@answers = yield(last_id: params[:last_id])
|
||||||
answer_ids = @answers.map(&:id)
|
answer_ids = @answers.map(&:id)
|
||||||
@answers_last_id = answer_ids.min
|
@answers_last_id = answer_ids.min
|
||||||
answer_ids += @pinned_answers.pluck(:id) if @pinned_answers.present?
|
@more_data_available = !yield(last_id: @answers_last_id, size: 1).select("answers.id").count.zero?
|
||||||
@more_data_available = !yield(last_id: @answers_last_id, size: 1).count.zero?
|
|
||||||
|
|
||||||
return unless user_signed_in?
|
|
||||||
|
|
||||||
@reacted_answer_ids = Reaction.where(user: current_user, parent_type: "Answer", parent_id: answer_ids).pluck(:parent_id)
|
|
||||||
@subscribed_answer_ids = Subscription.where(user: current_user, answer_id: answer_ids).pluck(:answer_id)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,15 +8,11 @@ class DiscoverController < ApplicationController
|
||||||
|
|
||||||
top_x = 10 # only display the top X items
|
top_x = 10 # only display the top X items
|
||||||
|
|
||||||
@popular_answers = Answer.where("created_at > ?", Time.now.ago(1.week)).order(:smile_count).reverse_order.limit(top_x).includes(:question, :user, :comments)
|
@popular_answers = Answer.for_user(current_user).where("created_at > ?", Time.now.ago(1.week)).order(:smile_count).reverse_order.limit(top_x).includes(:question, :user, :comments)
|
||||||
@most_discussed = Answer.where("created_at > ?", Time.now.ago(1.week)).order(:comment_count).reverse_order.limit(top_x).includes(:question, :user, :comments)
|
@most_discussed = Answer.for_user(current_user).where("created_at > ?", Time.now.ago(1.week)).order(:comment_count).reverse_order.limit(top_x).includes(:question, :user, :comments)
|
||||||
@popular_questions = Question.where("created_at > ?", Time.now.ago(1.week)).order(:answer_count).reverse_order.limit(top_x).includes(:user)
|
@popular_questions = Question.where("created_at > ?", Time.now.ago(1.week)).order(:answer_count).reverse_order.limit(top_x).includes(:user)
|
||||||
@new_users = User.where("asked_count > 0").order(:id).reverse_order.limit(top_x).includes(:profile)
|
@new_users = User.where("asked_count > 0").order(:id).reverse_order.limit(top_x).includes(:profile)
|
||||||
|
|
||||||
answer_ids = @popular_answers.map(&:id) + @most_discussed.map(&:id)
|
|
||||||
@reacted_answer_ids = Reaction.where(user: current_user, parent_type: "Answer", parent_id: answer_ids).pluck(:parent_id)
|
|
||||||
@subscribed_answer_ids = Subscription.where(user: current_user, answer_id: answer_ids).pluck(:answer_id)
|
|
||||||
|
|
||||||
# .user = the user
|
# .user = the user
|
||||||
# .question_count = how many questions did the user ask
|
# .question_count = how many questions did the user ask
|
||||||
@users_with_most_questions = Question.select('user_id, COUNT(*) AS question_count').
|
@users_with_most_questions = Question.select('user_id, COUNT(*) AS question_count').
|
||||||
|
|
|
@ -8,8 +8,7 @@ class QuestionController < ApplicationController
|
||||||
@answers = @question.cursored_answers(last_id: params[:last_id], current_user:)
|
@answers = @question.cursored_answers(last_id: params[:last_id], current_user:)
|
||||||
answer_ids = @answers.map(&:id)
|
answer_ids = @answers.map(&:id)
|
||||||
@answers_last_id = answer_ids.min
|
@answers_last_id = answer_ids.min
|
||||||
@more_data_available = !@question.cursored_answers(last_id: @answers_last_id, size: 1, current_user:).count.zero?
|
@more_data_available = !@question.cursored_answers(last_id: @answers_last_id, size: 1, current_user:).select("answers.id").count.zero?
|
||||||
@subscribed = Subscription.where(user: current_user, answer_id: answer_ids).pluck(:answer_id) if user_signed_in?
|
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html
|
format.html
|
||||||
|
|
|
@ -32,11 +32,9 @@ class TimelineController < ApplicationController
|
||||||
|
|
||||||
def paginate_timeline
|
def paginate_timeline
|
||||||
@timeline = yield(last_id: params[:last_id])
|
@timeline = yield(last_id: params[:last_id])
|
||||||
timeline_ids = @timeline.map(&:id)
|
timeline_ids = @timeline.select("answers.id").map(&:id)
|
||||||
@timeline_last_id = timeline_ids.min
|
@timeline_last_id = timeline_ids.min
|
||||||
@more_data_available = !yield(last_id: @timeline_last_id, size: 1).count.zero?
|
@more_data_available = !yield(last_id: @timeline_last_id, size: 1).select("answers.id").count.zero?
|
||||||
@reacted_answer_ids = Reaction.where(user: current_user, parent_type: "Answer", parent_id: timeline_ids).pluck(:parent_id)
|
|
||||||
@subscribed_answer_ids = Subscription.where(user: current_user, answer_id: timeline_ids).pluck(:answer_id)
|
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html { render "timeline/timeline" }
|
format.html { render "timeline/timeline" }
|
||||||
|
|
|
@ -8,8 +8,8 @@ class UserController < ApplicationController
|
||||||
after_action :mark_notification_as_read, only: %i[show]
|
after_action :mark_notification_as_read, only: %i[show]
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@pinned_answers = @user.answers.pinned.includes([{ user: :profile }, :question]).order(pinned_at: :desc).limit(10).load_async
|
@pinned_answers = @user.answers.for_user(current_user).pinned.includes([{ user: :profile }, :question]).order(pinned_at: :desc).limit(10).load_async
|
||||||
paginate_answers { |args| @user.cursored_answers(**args) }
|
paginate_answers { |args| @user.cursored_answers(current_user_id: current_user, **args) }
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html
|
format.html
|
||||||
|
|
|
@ -15,6 +15,20 @@ class Answer < ApplicationRecord
|
||||||
# rubocop:enable Rails/UniqueValidationWithoutIndex
|
# rubocop:enable Rails/UniqueValidationWithoutIndex
|
||||||
|
|
||||||
scope :pinned, -> { where.not(pinned_at: nil) }
|
scope :pinned, -> { where.not(pinned_at: nil) }
|
||||||
|
scope :for_user, lambda { |current_user|
|
||||||
|
next select("answers.*", "false as is_subscribed", "false as has_reacted") if current_user.nil?
|
||||||
|
|
||||||
|
select("answers.*",
|
||||||
|
"EXISTS(SELECT 1
|
||||||
|
FROM subscriptions
|
||||||
|
WHERE answer_id = answers.id
|
||||||
|
AND user_id = #{current_user.id}) as is_subscribed",
|
||||||
|
"EXISTS(SELECT 1
|
||||||
|
FROM reactions
|
||||||
|
WHERE parent_id = answers.id
|
||||||
|
AND parent_type = 'Answer'
|
||||||
|
AND user_id = #{current_user.id}) as has_reacted")
|
||||||
|
}
|
||||||
|
|
||||||
SHORT_ANSWER_MAX_LENGTH = 640
|
SHORT_ANSWER_MAX_LENGTH = 640
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,8 @@ module Answer::TimelineMethods
|
||||||
define_cursor_paginator :cursored_public_timeline, :public_timeline
|
define_cursor_paginator :cursored_public_timeline, :public_timeline
|
||||||
|
|
||||||
def public_timeline(current_user: nil)
|
def public_timeline(current_user: nil)
|
||||||
includes([{ user: :profile }, :question])
|
for_user(current_user)
|
||||||
|
.includes([{ user: :profile }, :question])
|
||||||
.then do |query|
|
.then do |query|
|
||||||
next query unless current_user
|
next query unless current_user
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ module List::TimelineMethods
|
||||||
# @return [ActiveRecord::Relation<Answer>] the lists' timeline
|
# @return [ActiveRecord::Relation<Answer>] the lists' timeline
|
||||||
def timeline(current_user: nil)
|
def timeline(current_user: nil)
|
||||||
Answer
|
Answer
|
||||||
|
.for_user(current_user)
|
||||||
.includes([{ user: :profile }, :question])
|
.includes([{ user: :profile }, :question])
|
||||||
.then do |query|
|
.then do |query|
|
||||||
next query unless current_user
|
next query unless current_user
|
||||||
|
|
|
@ -7,6 +7,7 @@ module Question::AnswerMethods
|
||||||
|
|
||||||
def ordered_answers(current_user: nil)
|
def ordered_answers(current_user: nil)
|
||||||
answers
|
answers
|
||||||
|
.for_user(current_user)
|
||||||
.includes([{ user: :profile }, :question])
|
.includes([{ user: :profile }, :question])
|
||||||
.then do |query|
|
.then do |query|
|
||||||
next query unless current_user
|
next query unless current_user
|
||||||
|
|
|
@ -6,8 +6,9 @@ module User::AnswerMethods
|
||||||
define_cursor_paginator :cursored_answers, :ordered_answers
|
define_cursor_paginator :cursored_answers, :ordered_answers
|
||||||
|
|
||||||
# @return [ActiveRecord::Relation<Answer>] List of a user's answers
|
# @return [ActiveRecord::Relation<Answer>] List of a user's answers
|
||||||
def ordered_answers
|
def ordered_answers(current_user_id:)
|
||||||
answers
|
answers
|
||||||
|
.for_user(current_user_id)
|
||||||
.order(:created_at)
|
.order(:created_at)
|
||||||
.reverse_order
|
.reverse_order
|
||||||
.includes(question: { user: [:profile] })
|
.includes(question: { user: [:profile] })
|
||||||
|
|
|
@ -8,6 +8,7 @@ module User::TimelineMethods
|
||||||
# @return [ActiveRecord::Relation<Answer>] the user's timeline
|
# @return [ActiveRecord::Relation<Answer>] the user's timeline
|
||||||
def timeline
|
def timeline
|
||||||
Answer
|
Answer
|
||||||
|
.for_user(self)
|
||||||
.then do |query|
|
.then do |query|
|
||||||
blocked_and_muted_user_ids = blocked_user_ids_cached + muted_user_ids_cached
|
blocked_and_muted_user_ids = blocked_user_ids_cached + muted_user_ids_cached
|
||||||
next query if blocked_and_muted_user_ids.empty?
|
next query if blocked_and_muted_user_ids.empty?
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
.dropdown-menu.dropdown-menu-end{ role: :menu }
|
.dropdown-menu.dropdown-menu-end{ role: :menu }
|
||||||
- if subscribed_answer_ids&.include?(answer.id)
|
- if answer.is_subscribed
|
||||||
= render "subscriptions/destroy", answer: answer
|
= render "subscriptions/destroy", answer: answer
|
||||||
- else
|
- else
|
||||||
= render "subscriptions/create", answer: answer
|
= render "subscriptions/create", answer: answer
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
- provide(:title, answer_title(@answer))
|
- provide(:title, answer_title(@answer))
|
||||||
- provide(:og, answer_opengraph(@answer))
|
- provide(:og, answer_opengraph(@answer))
|
||||||
.container-lg.container--main
|
.container-lg.container--main
|
||||||
= render "answerbox", a: @answer, display_all: @display_all, subscribed_answer_ids: @subscribed_answer_ids, reacted_answer_ids: @reacted_answer_ids
|
= render "answerbox", a: @answer, display_all: @display_all
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
%button.btn.btn-link.answerbox__action{ type: :button, name: "ab-smile", data: { a_id: a.id, action: reacted_answer_ids&.include?(a.id) ? :unsmile : :smile, selection_hotkey: "s" }, disabled: !user_signed_in? }
|
%button.btn.btn-link.answerbox__action{ type: :button, name: "ab-smile", data: { a_id: a.id, action: a.has_reacted ? :unsmile : :smile, selection_hotkey: "s" }, disabled: !user_signed_in? }
|
||||||
%i.fa.fa-fw.fa-smile-o
|
%i.fa.fa-fw.fa-smile-o
|
||||||
%span{ id: "ab-smile-count-#{a.id}" }= a.smile_count
|
%span{ id: "ab-smile-count-#{a.id}" }= a.smile_count
|
||||||
- unless display_all
|
- unless display_all
|
||||||
|
@ -13,4 +13,4 @@
|
||||||
.btn-group
|
.btn-group
|
||||||
%button.btn.btn-default.btn-sm.dropdown-toggle{ data: { bs_toggle: :dropdown }, aria: { expanded: false } }
|
%button.btn.btn-default.btn-sm.dropdown-toggle{ data: { bs_toggle: :dropdown }, aria: { expanded: false } }
|
||||||
%span.caret
|
%span.caret
|
||||||
= render "actions/answer", answer: a, subscribed_answer_ids:
|
= render "actions/answer", answer: a
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
.answerbox__answer-date
|
.answerbox__answer-date
|
||||||
= link_to(raw(t("time.distance_ago", time: time_tooltip(a))), answer_path(a.user.screen_name, a.id), data: { selection_hotkey: "l" })
|
= link_to(raw(t("time.distance_ago", time: time_tooltip(a))), answer_path(a.user.screen_name, a.id), data: { selection_hotkey: "l" })
|
||||||
.col-md-6.d-flex.d-md-block.answerbox__actions
|
.col-md-6.d-flex.d-md-block.answerbox__actions
|
||||||
= render "answerbox/actions", a:, display_all:, subscribed_answer_ids:, reacted_answer_ids:
|
= render "answerbox/actions", a:, display_all:
|
||||||
- else
|
- else
|
||||||
.row
|
.row
|
||||||
.col-md-6.text-start.text-muted
|
.col-md-6.text-start.text-muted
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
%i.fa.fa-thumbtack
|
%i.fa.fa-thumbtack
|
||||||
= t(".pinned")
|
= t(".pinned")
|
||||||
.col-md-6.d-md-flex.answerbox__actions
|
.col-md-6.d-md-flex.answerbox__actions
|
||||||
= render "answerbox/actions", a:, display_all:, subscribed_answer_ids:, reacted_answer_ids:
|
= render "answerbox/actions", a:, display_all:
|
||||||
.card-footer{ id: "ab-comments-section-#{a.id}", class: display_all.nil? ? "d-none" : nil }
|
.card-footer{ id: "ab-comments-section-#{a.id}", class: display_all.nil? ? "d-none" : nil }
|
||||||
= turbo_frame_tag("ab-reactions-list-#{a.id}", src: reactions_path(a.question, a), loading: :lazy) do
|
= turbo_frame_tag("ab-reactions-list-#{a.id}", src: reactions_path(a.question, a), loading: :lazy) do
|
||||||
.d-flex.smiles
|
.d-flex.smiles
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
.tab-pane.active.fade.show{ role: :tabpanel, id: "answers" }
|
.tab-pane.active.fade.show{ role: :tabpanel, id: "answers" }
|
||||||
- answers.each do |a|
|
- answers.each do |a|
|
||||||
= render "answerbox", a:, subscribed_answer_ids:, reacted_answer_ids:
|
= render "answerbox", a:
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
.tab-pane.fade{ role: :tabpanel, id: "comments" }
|
.tab-pane.fade{ role: :tabpanel, id: "comments" }
|
||||||
- comments.each do |a|
|
- comments.each do |a|
|
||||||
= render "answerbox", a:, subscribed_answer_ids:, reacted_answer_ids:
|
= render "answerbox", a:
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
%button.d-none{ data: { hotkey: "j", action: "navigation#down" } }
|
%button.d-none{ data: { hotkey: "j", action: "navigation#down" } }
|
||||||
%button.d-none{ data: { hotkey: "k", action: "navigation#up" } }
|
%button.d-none{ data: { hotkey: "k", action: "navigation#up" } }
|
||||||
- @answers.each do |a|
|
- @answers.each do |a|
|
||||||
= render "answerbox", a:, show_question: false, subscribed_answer_ids: @subscribed_answer_ids, reacted_answer_ids: @reacted_answer_ids
|
= render "answerbox", a:, show_question: false
|
||||||
|
|
||||||
- if @more_data_available
|
- if @more_data_available
|
||||||
.d-flex.justify-content-center.justify-content-sm-start#paginator
|
.d-flex.justify-content-center.justify-content-sm-start#paginator
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
= turbo_stream.append "answers" do
|
= turbo_stream.append "answers" do
|
||||||
- @answers.each do |a|
|
- @answers.each do |a|
|
||||||
= render "answerbox", a:, show_question: false, subscribed_answer_ids: @subscribed_answer_ids, reacted_answer_ids: @reacted_answer_ids
|
= render "answerbox", a:, show_question: false
|
||||||
|
|
||||||
= turbo_stream.update "paginator" do
|
= turbo_stream.update "paginator" do
|
||||||
- if @more_data_available
|
- if @more_data_available
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
%button.d-none{ data: { hotkey: "j", action: "navigation#down" } }
|
%button.d-none{ data: { hotkey: "j", action: "navigation#down" } }
|
||||||
%button.d-none{ data: { hotkey: "k", action: "navigation#up" } }
|
%button.d-none{ data: { hotkey: "k", action: "navigation#up" } }
|
||||||
- @timeline.each do |answer|
|
- @timeline.each do |answer|
|
||||||
= render "answerbox", a: answer, subscribed_answer_ids: @subscribed_answer_ids, reacted_answer_ids: @reacted_answer_ids
|
= render "answerbox", a: answer
|
||||||
|
|
||||||
- if @more_data_available
|
- if @more_data_available
|
||||||
.d-flex.justify-content-center#paginator
|
.d-flex.justify-content-center#paginator
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
= turbo_stream.append "timeline" do
|
= turbo_stream.append "timeline" do
|
||||||
- @timeline.each do |answer|
|
- @timeline.each do |answer|
|
||||||
= render "answerbox", a: answer, subscribed_answer_ids: @subscribed_answer_ids, reacted_answer_ids: @reacted_answer_ids
|
= render "answerbox", a: answer
|
||||||
|
|
||||||
= turbo_stream.update "paginator" do
|
= turbo_stream.update "paginator" do
|
||||||
- if @more_data_available
|
- if @more_data_available
|
||||||
|
|
|
@ -4,11 +4,11 @@
|
||||||
%button.d-none{ data: { hotkey: "k", action: "navigation#up" } }
|
%button.d-none{ data: { hotkey: "k", action: "navigation#up" } }
|
||||||
#pinned-answers
|
#pinned-answers
|
||||||
- @pinned_answers.each do |a|
|
- @pinned_answers.each do |a|
|
||||||
= render "answerbox", a:, subscribed_answer_ids: @subscribed_answer_ids, reacted_answer_ids: @reacted_answer_ids
|
= render "answerbox", a:
|
||||||
|
|
||||||
#answers
|
#answers
|
||||||
- @answers.each do |a|
|
- @answers.each do |a|
|
||||||
= render "answerbox", a:, subscribed_answer_ids: @subscribed_answer_ids, reacted_answer_ids: @reacted_answer_ids
|
= render "answerbox", a:
|
||||||
|
|
||||||
- if @more_data_available
|
- if @more_data_available
|
||||||
.d-flex.justify-content-center.justify-content-sm-start#paginator
|
.d-flex.justify-content-center.justify-content-sm-start#paginator
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
= turbo_stream.append "answers" do
|
= turbo_stream.append "answers" do
|
||||||
- @answers.each do |a|
|
- @answers.each do |a|
|
||||||
= render "answerbox", a:, subscribed_answer_ids: @subscribed_answer_ids, reacted_answer_ids: @reacted_answer_ids
|
= render "answerbox", a:
|
||||||
|
|
||||||
= turbo_stream.update "paginator" do
|
= turbo_stream.update "paginator" do
|
||||||
- if @more_data_available
|
- if @more_data_available
|
||||||
|
|
Loading…
Reference in New Issue