notification and activity
Bài đăng này đã không được cập nhật trong 7 năm
I.Activity
Thêm gem** 'public_activity'** sau đó bundle Tiếp tục tạo model nhé
+ rails g public_activity:migration
+ rake db:migrate
Xem trong db vừa tạo gồm những trường gì class CreateActivities < ActiveRecord::Migration
def self.up
create_table :activities do |t|
t.belongs_to :trackable, :polymorphic => true
t.belongs_to :owner, :polymorphic => true
t.string :key
t.text :parameters
t.belongs_to :recipient, :polymorphic => true
t.boolean :read, default: false # trường này mình thêm vào
t.boolean :enable, default: true # trường này mình thêm vào
t.integer :activity_type, default: 0 # trường này mình thêm vào
t.references :user # trường này mình thêm vào để tạo quan hệ với bảng user
t.timestamps
end
add_index :activities, [:trackable_id, :trackable_type]
add_index :activities, [:owner_id, :owner_type]
add_index :activities, [:recipient_id, :recipient_type]
end
# Drop table
def self.down
drop_table :activities
end
end
Nếu bạn muốn thêm 1 số trường thì đơn giản chỉ tạo 1 model mới rồi kế thừa nó
class Activity < PublicActivity::Activity
belongs_to :user
end
Bây giờ các bạn có thể gọi Activity.new xem nó có những trường nào nhé
Activity.new
#<Activity id: nil, trackable_type: nil, trackable_id: nil, owner_type: nil, owner_id: nil, key: nil, parameters: {}, recipient_type: nil,
recipient_id: nil, read: false, enable: true, activity_type: "active", user_id: nil, created_at: nil, updated_at: nil>
Trước tiên muốn sử dụng được thì các bạn làm như sau:
- include "include PublicActivity::Model" vào ApplicationRecord
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
include PublicActivity::Model
end
- Sau đó gọi "tracked" vào model nào bạn muốn luôn tất cả hành động của nó
class User < ApplicationRecord
tracked
end
Như vậy là xong, ngoài ra bạn có thể override lại nó
II.Notification
Tiếp tục nhé, mình tạo 1 model Notification cũng kế thừa PublicActivity::Activity
class Notification < PublicActivity::Activity
scope :all_notify, ->{where activity_type: 1} # mình thêm scope này để lọc theo Notification
end
Cũng như trên, đơn giản .....
Giờ mình sẽ hưỡng dẫn realtime Trước tiên :
- rails g channel Notify app/channels/notify_channel.rb
class NotifyChannel < ApplicationCable::Channel
def subscribed
stream_from "notify_chanel"
end
def unsubscribed
stop_all_streams
end
end
app/assets/javascripts/channels/notify.coffee
App.notify = App.cable.subscriptions.create "NotifyChannel",
connected: ->
# Called when the subscription is ready for use on the server
disconnected: ->
# Called when the subscription has been terminated by the server
received: (data) ->
# data
Tiếp tục: rails g job NotificationBroadcastJob
class NotificationBroadcastJob < ApplicationJob
queue_as :default
# ở đây các bạn override nó
def perform count, notification
ActionCable.server.broadcast "notify_channel", counter: render_count_notiication(count)
end
def render_count_notiication count
ApplicationController.renderer.render partial: "layouts/count_notification",
locals: {count_notification: count}
end
end
- ở controller
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :load_notifications, if: :user_signed_in?
def load_notifications
# Bạn nhớ lọc ra nhưng record của notification thôi nhé, vì mình dùng chùng 1 table kế thừa, viết scope theo activity_type
@notifications = current_user.Notification.all_notify.count
end
end
+ở view
application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>ElearningV1</title>
....
<%= action_cable_meta_tag %>
...
</head>
<span class="label label-warning" id="notification-counter">
<%= render partial: "layouts/count_notification",
locals: {count_notification: @notifications} %>
</span>
... /views/layouts/_count_notification.html.erb
<%= count_notification %>
- config/routes.rb
Rails.application.routes.draw do
...
mount ActionCable.server => '/cable'
...
end
Bây giờ muốn nó hoạt động: Bạn tạo 1 Notification
application_helper.rb
module ApplicationHelper
...
def create_notification_for_member model, object, name, user_id
Notification.create trackable_type: model, trackable_id: object.id,
owner_type: current_user.role, owner_id: current_user.id, key: name,
activity_type: Notification.activity_types[:notice], user_id: user_id
end
...
end
Trước hết bạn đã tạo 1 model user nhé Mình tạo 1 user mới nhé
- users_controller.rb
def create
@user = User.new user_params
if @user.save
create_notification_for_member User.name, @user, "create", @user.id
flash[:success] = t "devise.registrations.signed_up"
redirect_to admins_users_path
else
render :new
end
end
class Notification < PublicActivity::Activity
after_create :send_notification
def send_notification
NotificationBroadcastJob.perform_now Notification.all_notify.count, self
end
end
Bạn sửa lại file notify.coffee nhé
App.notify = App.cable.subscriptions.create "NotifyChannel",
connected: ->
# Called when the subscription is ready for use on the server
disconnected: ->
# Called when the subscription has been terminated by the server
received: (data) ->
this.update_counter(data.counter)
update_counter: (counter) ->
$counter = $('#notification-counter')
val = parseInt $counter.text()
val++
$counter
.text(val)
.css({top: '-10px'})
=> Sau khi tạo đối tượng notification xong thì nó sẽ thực hiện gọi NotificationBroadcastJob.perform rồi ra view, ở view chúng ta có file notify.coffee sẽ bắt kếnh truyền đó
++++ Bây giờ bạn muốn gửi đên từng user mà bạn muốn, MÌnh nghĩ bạn nên tạo 1 model để thấy rõ hành động này.. vì nãy giờ thực hiện tạo notification sau khi tạo 1 user. Nhưng bây giờ mình gửi notification cho user. nên bạn hạy tọ thêm 1 model. và model này chưa id người tạo. vd: rails g model Course user:references name:string Bây giờ bạn thêm trong CourseController.rb
def create
@course = Course.new course_params
if @course.save
flash[:success] = t "devise.registrations.signed_up"
create_notification_for_member Course.name, @course, "create", @course.user_id
redirect_to courses_path
else
render :new
end
end
trước hết các bạn tạo kết nối cho nó: app/chanels/application_cable/connection.rb
module ApplicationCable
class Connection < ActionCable::Connection::Base
identified_by :current_user
def connect
self.current_user = find_verified_user
logger.add_tags "ActionCable", current_user.email
end
protected
def find_verified_user
if current_user = User.find_by(id: cookies.signed["user.id"])
current_user
else
reject_unauthorized_connection
end
end
end
end
Bạn kiểm tra kết nối có thành công không. Nếu không kết nối đc chứng tỏ nó k lấy được cookies của các user đang đăng nhập, thì bạn thêm 1 file này : ../config/initializers/warden_hooks.rb
Warden::Manager.after_set_user do |user, auth, opts|
scope = opts[:scope]
auth.cookies.signed["#{scope}.id"] = user.id
auth.cookies.signed["#{scope}.expires_at"] = 30.minutes.from_now
end
Warden::Manager.before_logout do |user, auth, opts|
scope = opts[:scope]
auth.cookies.signed["#{scope}.id"] = nil
auth.cookies.signed["#{scope}.expires_at"] = nil
end
Bây giờ các bạn sữa lại
- file ../noitify_chanel.rb
class NotifyChannel < ApplicationCable::Channel
def subscribed
stream_from "notify_channel_#{current_user.id}"
end
def unsubscribed
end
end
- file ../notification_broadcast_job.rb
class NotificationBroadcastJob < ApplicationJob
queue_as :default
# ở đây các bạn override nó
def perform count, notification
# ở trên khi tạo 1 notification mình có lưu id người nhận là user_id, nên kênh truyên đi cho những người đang đăng nhập đúng id đó sẽ được nhận
ActionCable.server.broadcast "notify_channel_#{notification.user_id}", counter: render_count_notiication(count)
end
def render_count_notiication count
ApplicationController.renderer.render partial: "layouts/count_notification",
locals: {count_notification: count}
end
end
Chúc các bạn thành công, Link tham khảo: activity: https://github.com/chaps-io/public_activity notification: https://gist.github.com/excid3/4ca7cbead79f06365424b98fa7f8ecf6
All rights reserved