我有一个通知页面,我只想显示用户没有看到的通知。我试图通过发出每个通知来做到这一点:read =>默认为false但将其更改为:read =>当用户点击通知链接('.bell'类)时为true。问题是它改为=>确切地说,当用户点击链接时,所以当通知页面加载时,所有内容都已被“读取”,并且它什么也没有显示。我不确定如何在页面加载之前延迟此更改。
在我的控制器中我有这个:
def notifications
@activities = PublicActivity::Activity.order("created_at desc").where(recipient_id: current_user.id)
@notification_count = @activities.where(:read => false).count
end
def read_all_notifications
PublicActivity::Activity.where(recipient_id: current_user.id).update_all(:read => true)
end
然后在我的路线中:
get 'users/:id/allnotifications', to: 'users#allnotifications', as: :allnotifications
post 'users/read_all_notifications', to: 'users#read_all_notifications', as: :read_all_notifications
并在users.js.coffee中:
$(document).on 'click' , '.bell' , (e)->
$.ajax '/users/read_all_notifications' ,
type: "post"
dataType: "json"
beforeSend: (xhr) ->
xhr.setRequestHeader "X-CSRF-Token", $("meta[name=\"csrf-token\"]").attr("content")
cache: false
修改
我现在把它放在通知视图的底部:
<script>
$(document) ()->
$.ajax '/users/read_all_notifications' ,
type: "post"
dataType: "json"
beforeSend: (xhr) ->
xhr.setRequestHeader "X-CSRF-Token", $("meta[name=\"csrf-token\"]").attr("content")
cache: false
</script>
答案 0 :(得分:4)
我可能完全没有想到这一点,但是,你的应用程序/逻辑中的任何理由都不能只在你的控制器中使用after_action?
<强>控制器强>
after_action :read_all_notifications
def notifications
@activities = PublicActivity::Activity.order("created_at desc").where(recipient_id: current_user.id)
@notification_count = @activities.where(:read => false).count
end
def read_all_notifications
PublicActivity::Activity.where(recipient_id: current_user.id).update_all(:read => true)
end
理论上,一旦控制器完成加载(并显示)页面,这将把所有未读通知标记为已读。
同样,如果有的话,我可能会低估你的问题和道歉,但是,我确实想提供这种可能的解决方案。
答案 1 :(得分:1)
<强>属性强>
使用state_machine
gems之一(state_machine
,aasm
,workflow
)
我们使用aasm
,主要是因为state_machine
不再有效。
#app/models/activity.rb
class Activity < ActiveRecord::Base
include AASM
aasm do
state :unread, :initial => true
state :read
event :open do
transitions :from => :unread, :to => :read
end
event :mark_as_read do
transitions :from => :read, :to => :unread
end
end
end
这将超过工程师&#34;您的要求,但肯定会为您提供使其成为可扩展所需的功能
通过包含其中一个宝石,它会自动填充表格中的state
属性。这更加冗长和不如使用标准布尔值那么简洁,但真正帮助你做的是为你提供面向对象的公共方法:
job = Job.new
job.sleeping? # => true
job.may_run? # => true
job.run
job.running? # => true
job.sleeping? # => false
job.may_run? # => false
job.run # => raises AASM::InvalidTransition
在您的情况下,您将拥有:
notification = PublicActivity::Activity.new
notification.read? # -> false
notification.unread? #-> true
notification.mark_as_read #-> "unread"
noticiation.open #-> "read"
notification.sate #-> "unread"
<强>协会强>
其次,您需要使用协会&amp; scopes来管理您的数据。
当您在foreign_key
上致电.where
时,您正在执行ActiveRecord 可能为您做的工作:
#app/models/public_activity/activity.rb
class PublicActivity::Activity < ActiveRecord::Base
#fields id | user_id | created_at | updated_at
belongs_to :user
#belongs_to :recipient, class_name: "User", foreign_key: "recipient_id" #-> received --only if user to user
scope :recent, -> { order created_at: desc }
scope :read, -> { where status: "read" }
end
#app/models/users.rb
class User < ActiveRecord::Base
has_many :notifications, class_name: "PublicActivity::Activity"
end
这可以让您调用以下内容:
current_user.notifications.recent.read
<强>过渡强>
因此,当通知页面加载时,所有内容都已被“读取”。而且它 没有显示。我不确定如何在页面之前延迟此更改 已加载。
根据我对您的请求的理解,只需使用延迟的ajax请求:
#config/routes.rb
resources :users do
resources :notifications, only: [:index, :show] do
post :read_all, on: :collection #-> domain.com/notifications/read_all
end
end
这将使您能够使用以下内容:
#app/controllers/notifications_controller.rb
class NotificationsController < ApplicationController
# before_action :set_user -> only needed if not using current_user
def index
@notifications = current_user.notifications
end
private
def set_user
@user = User.find params[:user_id]
end
end
它将使您能够使用延迟的Ajax请求,如下所示:
#app/assets/javascripts/delayed_ajax.js
jQuery(document).ready(function () {
setTimeout(update_read, 1000);
});
var update_read = function() {
$.ajax({
url: "users/....../read_all",
success: function(data) {
alert("Success");
}
});
};
上述javascript必须从您希望使用的视图中明确调用(或至少具有一些识别值以确定何时触发)。
这里的诀窍是它使用 ajax 。这一点的重要性在于,Ajax只能在页面加载后工作(确保您的问题不会重复),并且只会在一定时间后触发。
这应该对你有用
答案 2 :(得分:1)
我可能在这里遗漏了一些问题,但我相信你想要一个结果,当他们点击通知页面时,它会呈现所有未读通知,将未读数字保持在当前状态。 如果他们用户转到另一个页面,他们现在会看到0个未读通知(假设没有创建新通知),如果他们再次点击该链接,则看不到任何通知。
如果是这种情况,那么一个非常简单的解决方案就是
def notifications
#Get UNREAD activities AND force execution
@activities = PublicActivity::Activity.order("created_at desc").where(recipient_id: current_user.id).where(:read => false).all
@notification_count = @activities.where(:read => false).count
#Mark items read
PublicActivity::Activity.where(recipient_id: current_user.id).where(:read => false).update_all(:read => true)
end
请注意。查询稍有改动。 .all应该强制执行查询。
答案 3 :(得分:0)
我会在点击时删除侦听器,并在加载时将其添加到页面中。这样,一旦页面加载,就会触发ajax请求。
我假设你有一个通知模板文件(notifications.html.erb可能?)。这就是你应该要求你的js调用触发“将所有标记为已读”的地方。注意不要在users.js.coffee中保留js触发器,因为javascript文件可能在每个请求上加载,而不仅仅是在加载通知模板时。