帖子有点长,但我已经走进了死胡同。我对 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
我尝试实现与我正在向索引页面发送通知的类似逻辑。服务器日志似乎显示通知点广播正在通过广播到达客户端,但没有在前端呈现
您需要订阅流(动作电缆类型)并为通过该订阅到达的涡轮流设定目标:
# 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}
)