延迟从未读更新到读

时间:2014-09-21 03:46:57

标签: ruby-on-rails

我有一个通知页面,我只想显示用户没有看到的通知。我试图通过发出每个通知来做到这一点: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>

4 个答案:

答案 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_machineaasmworkflow

会更好

我们使用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文件可能在每个请求上加载,而不仅仅是在加载通知模板时。