2014-09-21 55 views
0

我有一个通知页面,我只想显示用户没有看到的通知。我试图通过使每个通知都做到这一点:默认情况下,读取=> false,但当用户点击通知链接('.bell'类)时将其更改为:read => true。问题在于,当用户点击链接时,它被更改为=> 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

我可能完全没有想到这一点,但是,你的应用/逻辑中的任何原因,你不能只在你的控制器中使用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

根本没有想法,这是有效的! – user2759575 2014-09-26 19:49:28

0

我会删除的点击收听,并且将它时,它转而装载添加到页面。这样,一旦加载页面,就会触发ajax请求。

我假设你有一个通知模板文件(notifications.html.erb也许?)。这就是你应该要求你的js调用来触发“全部标记为已读”的地方。注意不要将js触发器保留在users.js.coffee中,因为该JavaScript文件可能在每个请求上加载,而不仅仅是加载通知模板时。

+0

感谢您的回复。对于js来说,新的东西对我很好。我应该替换'$(document).on'click','.bell',(e) - >'行吗? – user2759575 2014-09-21 04:23:32

+0

它会像$(document)() - >(因为这是使用jquery进行文档加载的调用),但是又不能将它添加到users.js.coffee文件中。呈现后,您仍然需要将js片段调用添加到通知模板。 – 2014-09-21 05:56:24

+0

嗯,仍然没有运气。我用我认为的现在编辑了这个问题。 – user2759575 2014-09-21 18:51:31

1

属性

你会使用的state_machine gemsstate_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 

这将“在工程师”您的要求,但肯定会为你提供你需要使它扩展

通过包括这些宝石的一个功能,它会自动填充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" 

协会

其次,您需要使用关联& 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将仅工作,并且仅在一段时间后才会触发。

这应该为你工作

+0

我试图按照你的aasm建议,但在第一个问题时停下来。刚刚得到通知工作已经够难了,我觉得它有点太过分了。但是,你的延迟ajax例子正是我想要的。你介意告诉我如何让它在没有aasm的情况下工作(以及如何从我的视图中调用delayed_ajax.js)?我感谢帮助:) – user2759575 2014-09-21 18:26:18

+0

喜欢这个,但我迷失在'PublicActivity :: Activity'发生的'Activity'关联 – 2016-01-23 01:50:24

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应强制执行查询。

+0

感谢您的帮助。我尝试过这样的事情,但我认为我需要'after_action'来使其工作。再次感谢。 – user2759575 2014-09-26 19:51:38

+0

yup,after_action更好 – vereecjw 2014-09-29 08:07:26