在我的 Rails 应用程序中,当出现新通知时,我无法使用 Turbo 帧更新通知图标

问题描述 投票:0回答:1

帖子有点长,但我已经走进了死胡同。我对 Rails 比较陌生,但我正在开发一个应用程序,允许用户对评论发表评论和投票,当另一个用户投票/时,评论所有者应该收到通知(通过导航栏中通知图标旁边的点)对他们的评论发表评论。 我已经设置了通知,以便在创建投票或评论后立即在通知选项卡(索引)中显示新通知,但我正在努力应用相同的逻辑来更新导航栏中的图标(对于一个点当新通知到达索引时出现)。该点会在页面刷新后出现,但不会立即出现。 这是导航栏按钮:

<%= turbo_stream_from "notification_dot_#{current_user.id}" %>
<%= link_to notifications_path, class: "bottom_navbar-link position-relative #{'active' if current_page?(notifications_path)}" do %>
  <i class="fas fa-bell"></i>
    <% if current_user.notifications.where(read: false).any? %>
      <span class="notification-dot"><i class="fa-solid fa-circle"></i></span>
    <% end %>
<% end %>

和通知索引页面

<%= turbo_stream_from "notifications_#{current_user.id}" %>

<div class="notifications-list" id="notifications-list">
  <% if @notifications.any? %>
    <% @notifications.each do |notification| %>
      <%= render notification %>
    <% end %>
  <% else %>
    <p>Nothing to see here...</p>
  <% end %>

这是用于出现在通知图标旁边的点的部分

<% if user.notifications.where(read: false).exists? %>
  <span class="notification-dot"><i class="fa-solid fa-circle"></i></span>
<% end %>

最后是评论/投票模型,将通知广播到索引页面(工作),并广播点以在有未读通知时立即出现(不工作)

class Comment < ApplicationRecord
  belongs_to :review
  belongs_to :user
  has_many :notifications, dependent: :destroy

  validates :content, presence: true, length: { minimum: 3, maximum: 140 }

  after_create_commit :broadcast_comment, :broadcast_comment_count
  after_destroy_commit :broadcast_comment_count

  after_create :notify_review_owner

  private

  def broadcast_comment
    broadcast_prepend_to "review_#{review.id}_comments",
                         target: "comments-#{review.id}",
                         partial: "comments/comment",
                         locals: { comment: self, user: self.user }
  end

  def broadcast_comment_count
    broadcast_replace_to "review_#{review.id}_comments",
                         target: "comment-count-#{review.id}",
                         partial: "comments/comment_count",
                         locals: { review: review }
  end

  def notify_review_owner
    return if user == review.user

    notification = Notification.create(
      user: review.user,
      comment: self,
      notification_type: 'comment',
      content: "#{user.username} commented on your review.",
      read: false
    )

    Rails.logger.info "Notification created: #{notification.inspect}"
    Rails.logger.info "Broadcasting notification dot update for User ID: #{review.user.id}"

    broadcast_replace_to(
      "notification_dot_#{review.user.id}",
      target: "notification_dot_#{review.user.id}",
      partial: "notifications/notification_dot",
      locals: { user: review.user }
    )

    broadcast_prepend_later_to(
      "notifications_#{review.user.id}",
      target: "notifications-list",
      partial: "notifications/notification",
      locals: { notification: notification }
    )
  end
end
class Vote < ApplicationRecord
  belongs_to :review
  belongs_to :user
  has_many :notifications, dependent: :destroy

  validates :user_id, uniqueness: { scope: :review_id, message: "You can only vote once on a review" }

  after_create :notify_review_owner

  private

  def notify_review_owner # rubocop:disable Metrics/MethodLength
    return if user == review.user

    notification = Notification.create(
      user: review.user,
      vote_id: self.id,
      notification_type: 'vote',
      content: "#{user.username} upvoted your review.",
      read: false
    )

    Rails.logger.info "Notification created: #{notification.inspect}"
    Rails.logger.info "Broadcasting notification dot update for User ID: #{review.user.id}"

    broadcast_replace_to(
      "notification_dot_#{review.user.id}",
      target: "notification_dot_#{review.user.id}",
      partial: "notifications/notification_dot",
      locals: { user: review.user }
    )

    broadcast_prepend_later_to(
      "notifications_#{review.user.id}",
      target: "notifications-list",
      partial: "notifications/notification",
      locals: { notification: notification }
    )
  end
end

我尝试实现与我正在向索引页面发送通知的类似逻辑。服务器日志似乎显示通知点广播正在通过广播到达客户端,但没有在前端呈现

ruby-on-rails websocket actioncable turbo
1个回答
0
投票

您需要订阅流(动作电缆类型)并为通过该订阅到达的涡轮流设定目标:

# subscribe
<%= turbo_stream_from "notification_dot", current_user %>

<%= link_to notifications_path,
  class: ["bottom_navbar-link position-relative", active: current_page?(notifications_path)] do %>

  <i class="fas fa-bell"></i> <!--/-->
  <%= render "notifications/notification_dot" %>
<% end %>

如果您使用

replace
操作,您需要在部分中替换整个div:

# app/views/notifications/_notification_dot.html.erb

# target
<%= tag.div id: "notification_dot_#{current_user.id}" do %>
  <% if current_user.notifications.where(read: false).any? %>
    <span class="notification-dot"><i class="fa-solid fa-circle"></i></span>
  <% end %>
<% end %>

并从模特处广播:

broadcast_replace_to(
  "notification_dot", review.user,              # stream name matching turbo_stream_from
  target: "notification_dot_#{review.user.id}", # a div you want to replace
  partial: "notifications/notification_dot",
  locals: {current_user: review.user}
)
© www.soinside.com 2019 - 2024. All rights reserved.