Skip to content

Commit

Permalink
Merge pull request #307 from joyofrails/feat/revisit-poll-vote-turbo-…
Browse files Browse the repository at this point in the history
…streams

In which I reinstate turbo_stream#replace for polls
  • Loading branch information
rossta authored Dec 7, 2024
2 parents 80fe072 + ffe13b8 commit a81bd27
Show file tree
Hide file tree
Showing 9 changed files with 100 additions and 65 deletions.
9 changes: 7 additions & 2 deletions app/controllers/share/polls/votes_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,16 @@ def create
@vote = @question.votes.find_by(device_uuid: ensure_device_uuid)
@vote ||= record_vote(@answer)

@question.broadcast_replace_later \
target: [@question, :results],
html: Share::Polls::Results.new(@poll, @question).call(view_context:),
attributes: {method: :morph}

if @vote.valid?
respond_to do |format|
format.html { redirect_to [:share, @poll] }
format.html { redirect_to [:share, @poll], notice: "Thank you for voting!".emojoy }
format.turbo_stream do
flash.now[:notice] = "Thank you for voting!"
flash.now[:notice] = "Thank you for voting!".emojoy
render turbo_stream: [
turbo_stream.prepend("flash", partial: "application/flash"),
turbo_stream.replace(@poll, renderable: Share::Polls::PollComponent.new(@poll, device_uuid: ensure_device_uuid))
Expand Down
2 changes: 0 additions & 2 deletions app/models/polls/question.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@ class Polls::Question < ApplicationRecord

scope :ordered, -> { order(position: :asc, id: :asc) }

broadcasts_refreshes

def votes_count
answers.sum(&:votes_count)
end
Expand Down
31 changes: 31 additions & 0 deletions app/views/share/polls/ballot.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
module Share
module Polls
class Ballot < ApplicationComponent
include Phlex::Rails::Helpers::ButtonTo
include Phlex::Rails::Helpers::DOMID
include Phlex::Rails::Helpers::Pluralize

attr_reader :poll, :question

def initialize(poll, question, voted: false)
@poll = poll
@question = question
@voted = voted
end

def view_template
div id: dom_id(question, :ballot), class: "question flex flex-col gap-2" do
p { question.body }

question.answers.ordered.each do |answer|
div id: dom_id(answer) do
button_to answer.body,
share_poll_votes_path(poll, answer_id: answer.id),
class: "button transparent slim"
end
end
end
end
end
end
end
12 changes: 2 additions & 10 deletions app/views/share/polls/lazy_page_poll.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module Share
module Polls
class LazyPagePoll < ApplicationComponent
include Phlex::Rails::Helpers::Provide
include Phlex::Rails::Helpers::Request
include Phlex::Rails::Helpers::TurboFrameTag
include Phlex::Rails::Helpers::TurboRefreshesWith

attr_reader :page, :title, :question_data
Expand All @@ -14,15 +14,7 @@ def initialize(page, title, question_data = {})

def view_template
poll = Poll.generate_for(page, title, question_data) or return

provide :head, turbo_refreshes_with(method: :morph, scroll: :preserve)
render Share::Polls::PollComponent.new(poll, device_uuid: device_uuid)
end

def device_uuid
return "" unless helpers.request.key_generator

helpers.cookies.signed[:device_uuid]
turbo_frame_tag poll, src: share_poll_path(poll), class: "poll"
end
end
end
Expand Down
6 changes: 3 additions & 3 deletions app/views/share/polls/poll_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ def view_template
.includes(:answers)
.ordered
.each do |question|
render Share::Polls::Question.new(
poll:,
question:,
render Share::Polls::QuestionComponent.new(
poll,
question,
voted: question.voted?(device_uuid: device_uuid)
)
end
Expand Down
31 changes: 31 additions & 0 deletions app/views/share/polls/question_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
module Share
module Polls
class QuestionComponent < ApplicationComponent
include Phlex::Rails::Helpers::TurboFrameTag
include Phlex::Rails::Helpers::TurboStreamFrom

attr_reader :poll, :question

def initialize(poll, question, voted: false)
@poll = poll
@question = question
@voted = voted
end

def view_template
turbo_frame_tag question, class: "question flex flex-col gap-2" do
if voted?
render Share::Polls::Results.new(poll, question)
else
render Share::Polls::Ballot.new(poll, question)
end
end
turbo_stream_from question
end

private

def voted? = !!@voted
end
end
end
Original file line number Diff line number Diff line change
@@ -1,59 +1,32 @@
module Share
module Polls
class Question < ApplicationComponent
include Phlex::Rails::Helpers::ButtonTo
include Phlex::Rails::Helpers::DOMID
class Results < ApplicationComponent
include Phlex::Rails::Helpers::Pluralize
include Phlex::Rails::Helpers::TurboFrameTag
include Phlex::Rails::Helpers::TurboStreamFrom
include Phlex::Rails::Helpers::DOMID

attr_reader :poll, :question

def initialize(poll:, question:, voted: false)
def initialize(poll, question)
@poll = poll
@question = question
@voted = voted
end

def view_template
turbo_frame_tag question, class: "question flex flex-col gap-2" do
if voted?
results
else
ballot
end
end
turbo_stream_from question
end

def ballot
p { question.body }
div id: dom_id(question, :results), class: "question flex flex-col gap-2" do
p { question.body }

question.answers.ordered.each do |answer|
div id: dom_id(answer) do
button_to answer.body,
share_poll_votes_path(poll, answer_id: answer.id),
class: "button transparent slim"
question.answers.ordered.each do |answer|
render AnswerBar.new(answer, question)
end
end
end

def results
p { question.body }

question.answers.ordered.each do |answer|
render AnswerBar.new(answer, question)
end

div(class: "p-2") do
p(class: "text-small font-extrabold") { pluralize question.votes_count, "vote" }
div(class: "p-2") do
p(class: "text-small font-extrabold") { pluralize question.votes_count, "vote" }
end
end
end

private

def voted? = !!@voted

class AnswerBar < ApplicationComponent
include Phlex::Rails::Helpers::DOMID
include Phlex::Rails::Helpers::NumberToPercentage
Expand Down
15 changes: 10 additions & 5 deletions spec/system/share/polls_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,15 @@
expect(page).to have_content("2 votes")
end

# We could theoretically test that the original user sees the refreshed
# results but I could only get this to work in system tests when the
# broadcast was emitted in process while "refresh later" via background job,
# as I would prefer it work, doesn’t seem to work with test adapters for
# solid cable / solid queue.
# Assert the vote results are broadcasted to the other guest session
perform_enqueued_jobs

within("#polls_answer_#{answer1.id}") do
expect(page).to have_content("50.0")
end
within("#polls_answer_#{answer2.id}") do
expect(page).to have_content("50.0%")
end
expect(page).to have_content("2 votes")
end
end
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
require "rails_helper"

RSpec.describe Share::Polls::Question, type: :view do
RSpec.describe Share::Polls::QuestionComponent, type: :view do
context "when not voted on" do
it "renders with no answers" do
poll = FactoryBot.create(:poll)
question = FactoryBot.create(:polls_question, poll:)

render described_class.new(poll:, question:, voted: false)
render described_class.new(poll, question, voted: false)

expect(rendered).to have_css("p")
end
Expand All @@ -16,7 +16,7 @@
question = FactoryBot.create(:polls_question, poll:)
FactoryBot.create(:polls_answer, question:)

render described_class.new(poll:, question:, voted: false)
render described_class.new(poll, question, voted: false)

expect(rendered).to have_css("button", count: 1)
end
Expand All @@ -27,7 +27,7 @@
FactoryBot.create(:polls_answer, question:)
FactoryBot.create(:polls_answer, question:)

render described_class.new(poll:, question:, voted: false)
render described_class.new(poll, question, voted: false)

expect(rendered).to have_css("button", count: 2)
end
Expand All @@ -39,7 +39,7 @@
question = FactoryBot.create(:polls_question, poll:)
FactoryBot.create(:polls_answer, question:)

render described_class.new(poll:, question:, voted: true)
render described_class.new(poll, question, voted: true)

expect(rendered).to have_css(".question")
expect(rendered).to have_css(".answer")
Expand All @@ -53,7 +53,7 @@
answer = FactoryBot.create(:polls_answer, question:)
FactoryBot.create(:polls_vote, answer:)

render described_class.new(poll:, question:, voted: true)
render described_class.new(poll, question, voted: true)

expect(rendered).to have_css(".question")
expect(rendered).to have_css(".answer")
Expand Down

0 comments on commit a81bd27

Please sign in to comment.