Episodes
dev said 9 months ago on Real-time Comments and Voting :
Why re-render the entire comment template? The code can be simplified
Partial comment
#app/views/comments/_comment.html.erb
<%= content_tag :div, id: dom_id(comment), class: "card mb-3" do %>
  <div class="card-body">
    <h5 class="card-title"><%= comment.user.email %> said:</h5>
    <p class="card-text"><%= comment.content %></p>
    <p id='<%= dom_id(comment)%>_count'>
      <%= comment.vote_count %>
    </p>
    <%= link_to "Up Vote", comment_votes_path(comment, choice: :up_vote, format: :turbo_stream), class: "card-link" %>
    <%= link_to "Down Vote", comment_votes_path(comment, choice: :down_vote, format: :turbo_stream), class: "card-link" %>
  </div>
<% end %>
model Vote
# app/models/vote.rb
after_update_commit do
  broadcast_update_to("comments", target: "#{dom_id(comment)}_count", html: comment.vote_count)
end


David Kimura PRO said 9 months ago on Real-time Comments and Voting :
I agree, and it's great to know. I tried to keep the examples as simple to follow as possible, but you're right, it should have been mentioned. Thanks!

gonzalezarthur said 9 months ago on Real-time Comments and Voting :
Hi!

I'm building a Twitter-like app in Rails 6.1.4.4, just to study the framework, and I'm trying to do the implementation you did in this video, but for tweets instead of post comments or votes.

I've written the Tweet model like this ("Tueet" is just another way of writing "Tweet"):
# models/tueet.rb

class Tueet < ApplicationRecord
  # Model broadcasts
  after_create_commit do
    broadcast_prepend_to :tueets,
    target: "tueets",
    partial: "tueets/tueet",
    locals: { tueet: self }
  end
end
In the code above I'm omitting the validation and relationships part of the model because they are working properly and have nothing to do with the broadcast implementation (I think).

For the Tueet controller I've wrote:
# controllers/tueets_controller.rb

class TueetsController < ApplicationController
  before_action :authenticate_user!, except: %i[ show ]
  before_action :set_tueet, only: %i[ show destroy ]

  def new
    @tueet = current_user.tueets.new
  end

  def create
    @tueet = current_user.tueets.new(tueet_params)
    respond_to do |format|
      if @tueet.save
        format.turbo_stream {
	  render turbo_stream: turbo_stream.replace(
	    "new_tueet",
	    partial: "tueets/form",
	    locals: { tueet: Tueet.new }
	  )
	}
      end
    end
  end
This implementation for the TueetsController is almost identical to what you've written for the example in the video.

I'm rendering the following form, from "tueets/form", in the Feed#index page:
# views/tueets/form.html.erb

<%= turbo_frame_tag "new_tueet", target: :_top do %>
  <%= simple_form_for(tueet) do |f| %>
    <%= f.input :body, label: false, placeholder: 'News, moments, ideas...', input_html: { class: 'w-full h-11 px-3 py-2 border border-gray-200 rounded-full', style: 'resize: none;' } %>
    <%= f.submit 'Post', class: 'h-11 px-4 cursor-pointer font-sans font-bold text-md text-white bg-gradient-to-r from-green-400 to-blue-500 rounded-full' %>		
  <% end %>
<% end %>

I'm doing this just like you did, using:
<%= turbo_frame_tag "new_tueet", src: new_tueet_path %>
The _form.html.erb partial as well as the _tweet.html.erb partial are stored within the "tueets" view folder, and the page where I'm trying to render them both is stored in the "feed" view folder (feed/index.html.erb).

So my feed/index page is something like this:
# views/feed/index.html.erb

<%= turbo_stream_from :tueets %>

<!-- Tueet form -->
<div class="w-full h-max p-3">
  <%= turbo_frame_tag "new_tueet", src: new_tueet_path %>		
</div>

<!-- Twueets -->		
<div id="tueets">
  <%= render @tueets %>
</div>

And the "tueets/_tueet.html.erb" form is written like this:
<%= content_tag :div, id: dom_id(tueet), class: 'w-full h-max p-3 flex flex-row items-start justify-start border-t border-gray-100 gap-2' do %>
  <%= tueet.body %>
<% end %>
Just like you did in the video.

My problem is that when I submit a Tueet from the form, it disappears instead of just refresh the partial. Also the Tueet just created is not broadcasted to the @tueets collection, so the page is not updated properly, and the form just became visible again when I refresh the page manually. :/

David Kimura PRO said 9 months ago on Real-time Comments and Voting :
  gonzalezarthur  any errors in the browser console or in the rails logs? 

dev said 9 months ago on Real-time Comments and Voting :
  gonzalezarthur Why does the model name Tueet (class Tueet < ApplicationRecord) have the file name tweet.rb (# models/tweet.rb)?

Some refactoring
class VotesController < ApplicationController
  ...
  def show
    @comment = Comment.find(params[:comment_id])
    @vote = Vote.find_or_create_by(user: current_user, comment: @comment)

    @vote.voted(params[:choice])
  end

class Vote < ApplicationRecord
  ...
  def voted(choice)
    return unless choice.in?(Vote::choices.keys)

    case choice
    when 'up_vote'
      up_vote? ? cancel! : up_vote!
    when 'down_vote'
      down_vote? ? cancel! : down_vote!
    end
  end




gonzalezarthur said 9 months ago on Real-time Comments and Voting :
  David Kimura I just figured out the problem.

I was trying to render the tueets like this:
<% if @tueets.empty? %>
  <span>No tweets!</span>
<% else %>
  <div id="tueets">	
    <%= render @tueets %>
  </div>
<% end %>
Well, it seems that if I put the tueets div inside a logical condition, the partial doesn't get updated properly until that condition gets resolved. I removed that if statement and the page is updating as it should.

Thank you anyway!

Christian Malpeli PRO said 9 months ago on Real-time Comments and Voting :
Thanks for the video!  Would be great if you did a video showing how to interact with Flash and Model Errors as part of Hotwire....

dev said 9 months ago on Real-time Comments and Voting :
My project, which is based on the source code from this video. 

Fixed

  • bugs in the Votes model (has_many :votes, dependent: :destroy move to User model ).

Added new feature:

  • The title of the vote button changes depending on user actions: up_vote(down_vote) -> undo_vote -> up_vote(down_vote). Title change usually only for current users (Stimulus controller);
  • Unauthenticated users cannot vote on a comment (Stimulus controller );
  • The user who voted will receive a flash message with information;
  • Added the ability for the author of a comment to delete it (Stimulus controller);
  • Hotwire flash messages (lTailwind style);
  • Autohide and manual closing of Hotwire flash messages (Bootstrap JS and Stimulus controller);
  • Comments counter that changes dynamically after adding/removing objects (broadcasts html).
  • Counter votes, rewritten only on broadcasts HTML parts;
  • Small refactoring code

diazgio said 8 months ago on Real-time Comments and Voting :
I'm having troubles with to render the form in rails 7 I don't have any comment and the form for the new comment is not there. And I can no't add the rich text to the form also is just not appearing at all in the forms.

David Kimura PRO said 8 months ago on Real-time Comments and Voting :
Check your browser console for any errors or warnings.

diazgio said 8 months ago on Real-time Comments and Voting :
No errors, I was building everything from scratch using rails new VotingApp --css=bootstrap --database=postgresql and It is not recognizing neither rich text nor turboflame

David Kimura PRO said 8 months ago on Real-time Comments and Voting :
Is the project public on gitlab/github so that I might check it out?


David Kimura PRO said 8 months ago on Real-time Comments and Voting :
Hmmm. not sure what the issue is that you're seeing, but I am able to pull down your project and see the actiontext.


diazgio said 8 months ago on Real-time Comments and Voting :
I am using chrome and mozilla to open the code and is not appearing :s

David Kimura PRO said 8 months ago on Real-time Comments and Voting :
How did you start the rails server? You should use bin/dev since that will start the rails app, css and js assets monitoring.

nelsonchavespro said 6 months ago on Real-time Comments and Voting :
man I am struggling with this. I'm trying to implement this on a discussions/posts that's different from yours. And the likes work but i have to refresh the page. I get a "No template found for Discussions::VotesController#show, rendering head :no_content" on the console.

nelsonchavespro said 6 months ago on Real-time Comments and Voting :
Yes! I figured it out by accident lol it worked. I followed the last part by what the first guy posted.   and that worked for me perfectly

marvinick said 6 months ago on Real-time Comments and Voting :
This is great, thank you!

nelsonchavespro said 4 months ago on Real-time Comments and Voting :
is there a way to query this or scope whatever is best? So I can display the comments highest to lowest? The comment with the highest votes displays first

Stephane PAQUET PRO said 3 months ago on Real-time Comments and Voting :
  nelsonchavespro I do not think so. From what I found out, you have to implement this logic in a Stimulus controller. There is an example from DHH in a comment about this feature request in GitHub.
Here is a thread about this topic on Reddit with all the links I found: https://www.reddit.com/r/rails/comments/vntbl3/best_way_to_deal_with_sorted_data_in_a_stream/ feel free to contradict me if you find a better way.
Cheers

Login to Comment