action_cable_notifications 0.1.28 → 0.1.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +17 -5
- data/app/assets/javascripts/action_cable_notifications/collection.coffee +22 -6
- data/app/assets/javascripts/action_cable_notifications/default_callbacks.coffee +4 -4
- data/app/assets/javascripts/action_cable_notifications/store.coffee +4 -5
- data/lib/action_cable_notifications/channel.rb +55 -42
- data/lib/action_cable_notifications/channel_actions.rb +3 -2
- data/lib/action_cable_notifications/channel_cache.rb +44 -0
- data/lib/action_cable_notifications/hash_db.rb +111 -0
- data/lib/action_cable_notifications/model.rb +38 -35
- data/lib/action_cable_notifications/version.rb +1 -1
- metadata +5 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 64f6e0167fd97bc6b64dc43e1292c331cf7baff7
|
4
|
+
data.tar.gz: bf24e8703a9953a7be75a3d80f73deb27a118508
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 624a3425d47cd3ea0291abdc706a7b3bc5c12c5d19715775012c364b70d4b00d30907399b3c161357012bca7b33ca4f9afd48ab6f09b4fd95f21c048444b8d1b
|
7
|
+
data.tar.gz: 2848f179da19c2af48b313e07ae81638e481beac62cef85734d9c888e86c10622ffda3230bc2aa091f3589a9434624eebffd805a8d76a9fec6cbc5bfc7c7cb03
|
data/README.md
CHANGED
@@ -19,9 +19,17 @@ class TestChannel < ApplicationCable::Channel
|
|
19
19
|
include ActionCableNotifications::Channel
|
20
20
|
|
21
21
|
def subscribed
|
22
|
+
# Config streaming for Customer model with default options
|
22
23
|
stream_notifications_for Customer
|
23
24
|
# Can have more than one ActiveRecord model streaming per channel
|
24
|
-
stream_notifications_for Invoice,
|
25
|
+
stream_notifications_for Invoice,
|
26
|
+
model_options: {
|
27
|
+
scope: {
|
28
|
+
limit: 5,
|
29
|
+
order: :id,
|
30
|
+
select: [:id, :customer_id, :seller_id, :amount]
|
31
|
+
}
|
32
|
+
}
|
25
33
|
end
|
26
34
|
|
27
35
|
def unsubscribed
|
@@ -40,10 +48,14 @@ stream_notifications_for(model, options = {}, &block)
|
|
40
48
|
* options: **(Hash)** - Options to be used for configuracion. Default options are:
|
41
49
|
```ruby
|
42
50
|
{
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
51
|
+
publication: model.model_name.collection, # Name of the pubsub stream
|
52
|
+
params: params, # Params sent when client subscribes
|
53
|
+
cache: false, # Turn off server-side cache of client-side data
|
54
|
+
model_options: {
|
55
|
+
actions: [:create, :update, :destroy], # Model callbacks to attach to
|
56
|
+
scope: :all # Default collection scope. Can be an ,Array or Hash
|
57
|
+
track_scope_changes: true # During model updates, checks if the changes affect scope inclusion of the resulting record
|
58
|
+
}
|
47
59
|
}
|
48
60
|
```
|
49
61
|
|
@@ -4,7 +4,7 @@ class CableNotifications.Collection
|
|
4
4
|
upstream = (command, params={}) ->
|
5
5
|
if @sync
|
6
6
|
cmd =
|
7
|
-
|
7
|
+
publication: @publication
|
8
8
|
command: command
|
9
9
|
params: params
|
10
10
|
|
@@ -38,7 +38,7 @@ class CableNotifications.Collection
|
|
38
38
|
|
39
39
|
# Public methods
|
40
40
|
#######################################
|
41
|
-
constructor: (@store, @name, @
|
41
|
+
constructor: (@store, @name, @publication=name, callbacks) ->
|
42
42
|
# Data storage array
|
43
43
|
@data = []
|
44
44
|
# Channel used to sync with upstream collection
|
@@ -50,8 +50,21 @@ class CableNotifications.Collection
|
|
50
50
|
# Stores records that needs to be tracked when inserted into the collection
|
51
51
|
@trackedRecords = []
|
52
52
|
|
53
|
+
@callbacks = {}
|
54
|
+
|
55
|
+
@observeChanges(callbacks)
|
56
|
+
|
53
57
|
@callbacks?.initialize?.call(this)
|
54
58
|
|
59
|
+
# Update the callback stack for collection
|
60
|
+
observeChanges: (new_callbacks) ->
|
61
|
+
_.each(new_callbacks, (cb, name) =>
|
62
|
+
old_cb = @callbacks?[name]
|
63
|
+
@callbacks[name] = () ->
|
64
|
+
cb.apply(this, arguments)
|
65
|
+
old_cb?.apply(this, arguments)
|
66
|
+
)
|
67
|
+
|
55
68
|
# Sync collection to ActionCable Channel
|
56
69
|
syncToChannel: (@channel) ->
|
57
70
|
@sync = true
|
@@ -93,7 +106,7 @@ class CableNotifications.Collection
|
|
93
106
|
record
|
94
107
|
|
95
108
|
# Creates a new record
|
96
|
-
create: (fields={}) ->
|
109
|
+
create: (fields={}, options={}) ->
|
97
110
|
record = _.find(@data, {id: fields.id})
|
98
111
|
if record
|
99
112
|
console.warn("[create] Not expected to find an existing record with id #{fields.id}")
|
@@ -108,6 +121,7 @@ class CableNotifications.Collection
|
|
108
121
|
if !@sync
|
109
122
|
@data.push (fields)
|
110
123
|
@callbacks?.create?.call(this, fields)
|
124
|
+
@callbacks?.changed?.call(this, @data) unless options.batching
|
111
125
|
|
112
126
|
upstream.call(this, "create", {fields: fields})
|
113
127
|
fields
|
@@ -117,20 +131,21 @@ class CableNotifications.Collection
|
|
117
131
|
record = _.find(@data, selector)
|
118
132
|
if !record
|
119
133
|
if options.upsert
|
120
|
-
@create(fields)
|
134
|
+
@create(fields, options)
|
121
135
|
else
|
122
136
|
console.warn("[update] Couldn't find a matching record:", selector)
|
123
137
|
else
|
124
138
|
if !@sync
|
125
139
|
@callbacks?.update?.call(this, selector, fields, options)
|
126
140
|
_.extend(record, fields)
|
141
|
+
@callbacks?.changed?.call(this, @data) unless options.batching
|
127
142
|
|
128
143
|
upstream.call(this, "update", {id: record.id, fields: fields})
|
129
144
|
record
|
130
145
|
|
131
146
|
# Update an existing record or inserts a new one if there is no match
|
132
|
-
upsert: (selector={}, fields) ->
|
133
|
-
@update(selector, fields, {upsert: true})
|
147
|
+
upsert: (selector={}, fields, options={}) ->
|
148
|
+
@update(selector, fields, _.extend(options, {upsert: true}))
|
134
149
|
|
135
150
|
# Destroy an existing record
|
136
151
|
destroy: (selector={}) ->
|
@@ -142,6 +157,7 @@ class CableNotifications.Collection
|
|
142
157
|
if !@sync
|
143
158
|
@data.splice(index, 1)
|
144
159
|
@callbacks?.destroy?.call(this, selector)
|
160
|
+
@callbacks?.changed?.call(this, @data) unless options.batching
|
145
161
|
|
146
162
|
upstream.call(this, "destroy", {id: record.id})
|
147
163
|
record
|
@@ -15,15 +15,15 @@ class CableNotifications.Store.DefaultCallbacks
|
|
15
15
|
collection.update({id: packet.id}, packet.data)
|
16
16
|
|
17
17
|
update_many: (packet, collection) ->
|
18
|
-
_.each packet.data, (fields) ->
|
19
|
-
collection.update({id: fields.id}, fields)
|
18
|
+
_.each packet.data, (fields, index, records) ->
|
19
|
+
collection.update({id: fields.id}, fields, {batching: index<records.length-1})
|
20
20
|
|
21
21
|
upsert: (packet, collection) ->
|
22
22
|
collection.upsert({id: packet.id}, packet.data)
|
23
23
|
|
24
24
|
upsert_many: (packet, collection) ->
|
25
|
-
_.each packet.data, (fields) ->
|
26
|
-
collection.upsert({id: fields.id}, fields)
|
25
|
+
_.each packet.data, (fields, index, records) ->
|
26
|
+
collection.upsert({id: fields.id}, fields, {batching: index<records.length-1})
|
27
27
|
|
28
28
|
destroy: (packet, collection) ->
|
29
29
|
collection.destroy({id: packet.id})
|
@@ -16,10 +16,10 @@ class CableNotifications.Store
|
|
16
16
|
# Then call original callback
|
17
17
|
packetReceived = (channelInfo) ->
|
18
18
|
(packet) ->
|
19
|
-
if packet?.
|
19
|
+
if packet?.publication
|
20
20
|
# Search if there is a collection in this Store that receives packets from the server
|
21
21
|
collection = _.find(channelInfo.collections,
|
22
|
-
{
|
22
|
+
{publication: packet.publication})
|
23
23
|
if collection
|
24
24
|
dispatchPacket.call(this, packet, collection)
|
25
25
|
channelInfo.callbacks.received?.apply(channelInfo.channel, arguments)
|
@@ -56,12 +56,11 @@ class CableNotifications.Store
|
|
56
56
|
#######################################
|
57
57
|
|
58
58
|
# Register a new collection
|
59
|
-
registerCollection: (name, channel,
|
60
|
-
tableName = name unless tableName
|
59
|
+
registerCollection: (name, channel, publication=name, actions) ->
|
61
60
|
if @collections[name]
|
62
61
|
console.warn "[registerCollection]: Collection '#{name}' already exists"
|
63
62
|
else
|
64
|
-
@collections[name] = new CableNotifications.Collection(this, name,
|
63
|
+
@collections[name] = new CableNotifications.Collection(this, name, publication, actions)
|
65
64
|
if channel
|
66
65
|
@syncToChannel(channel, @collections[name])
|
67
66
|
|
@@ -18,42 +18,46 @@ module ActionCableNotifications
|
|
18
18
|
#
|
19
19
|
# @param [Hash] data Contains command to be executed and its parameters
|
20
20
|
# {
|
21
|
-
# "
|
21
|
+
# "publication": "model.model_name.name"
|
22
22
|
# "command": "fetch"
|
23
23
|
# "params": {}
|
24
24
|
# }
|
25
25
|
def action(data)
|
26
26
|
data.deep_symbolize_keys!
|
27
27
|
|
28
|
-
|
28
|
+
publication = data[:publication]
|
29
|
+
channel_options = @ChannelPublications[publication]
|
29
30
|
if channel_options
|
30
31
|
model = channel_options[:model]
|
31
|
-
|
32
|
-
|
32
|
+
model_options = model.ChannelPublications[publication]
|
33
|
+
params = data[:params]
|
34
|
+
command = data[:command]
|
33
35
|
|
34
|
-
|
36
|
+
action_params = {
|
37
|
+
publication: publication,
|
35
38
|
model: model,
|
36
39
|
model_options: model_options,
|
37
|
-
|
38
|
-
|
40
|
+
options: channel_options,
|
41
|
+
params: params,
|
42
|
+
command: command
|
39
43
|
}
|
40
44
|
|
41
|
-
case
|
45
|
+
case command
|
42
46
|
when "fetch"
|
43
|
-
fetch(
|
47
|
+
fetch(action_params)
|
44
48
|
when "create"
|
45
|
-
create(
|
49
|
+
create(action_params)
|
46
50
|
when "update"
|
47
|
-
update(
|
51
|
+
update(action_params)
|
48
52
|
when "destroy"
|
49
|
-
destroy(
|
53
|
+
destroy(action_params)
|
50
54
|
end
|
51
55
|
else
|
52
56
|
response = {
|
53
|
-
|
57
|
+
publication: publication,
|
54
58
|
msg: 'error',
|
55
|
-
command:
|
56
|
-
error: "
|
59
|
+
command: command,
|
60
|
+
error: "Stream for publication '#{publication}' does not exist in channel '#{self.channel_name}'."
|
57
61
|
}
|
58
62
|
|
59
63
|
# Send error notification to the client
|
@@ -63,7 +67,7 @@ module ActionCableNotifications
|
|
63
67
|
|
64
68
|
def initialize(*args)
|
65
69
|
@collections = {}
|
66
|
-
@
|
70
|
+
@ChannelPublications = {}
|
67
71
|
super
|
68
72
|
end
|
69
73
|
|
@@ -92,38 +96,45 @@ module ActionCableNotifications
|
|
92
96
|
# @param [Hash] options Streaming options
|
93
97
|
#
|
94
98
|
def stream_notifications_for(model, options = {})
|
95
|
-
|
99
|
+
|
100
|
+
# Default publication options
|
96
101
|
options = {
|
97
|
-
|
98
|
-
params: params,
|
102
|
+
publication: model.model_name.name,
|
99
103
|
cache: false,
|
100
104
|
model_options: {},
|
101
|
-
|
102
|
-
}.merge(options)
|
105
|
+
scope: :all
|
106
|
+
}.merge(options).merge(params.deep_symbolize_keys)
|
103
107
|
|
104
108
|
# These options cannot be overridden
|
105
109
|
options[:model] = model
|
106
|
-
# options[:channel] = self
|
107
|
-
model_name = model.model_name.collection
|
108
110
|
|
109
|
-
|
110
|
-
@ActionCableNotificationsOptions[model_name] = options
|
111
|
+
publication = options[:publication]
|
111
112
|
|
112
|
-
# Checks if
|
113
|
-
if
|
114
|
-
|
115
|
-
|
113
|
+
# Checks if the publication already exists in the channel
|
114
|
+
if not @ChannelPublications.include?(publication)
|
115
|
+
# Sets channel options
|
116
|
+
@ChannelPublications[publication] = options
|
116
117
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
118
|
+
# Checks if model already includes notification callbacks
|
119
|
+
if !model.respond_to? :ChannelPublications
|
120
|
+
model.send('include', ActionCableNotifications::Model)
|
121
|
+
end
|
121
122
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
123
|
+
# Sets broadcast options if they are not already present in the model
|
124
|
+
if not model.ChannelPublications.key? publication
|
125
|
+
model.broadcast_notifications_from publication, options[:model_options]
|
126
|
+
else # Reads options configuracion from model
|
127
|
+
options[:model_options] = model.ChannelPublications[publication]
|
128
|
+
end
|
129
|
+
|
130
|
+
# Start streaming
|
131
|
+
stream_from publication, coder: ActiveSupport::JSON do |packet|
|
132
|
+
packet.merge!({publication: publication})
|
133
|
+
transmit_packet(packet, options)
|
134
|
+
end
|
135
|
+
# XXX: Transmit initial data
|
126
136
|
|
137
|
+
end
|
127
138
|
end
|
128
139
|
|
129
140
|
#
|
@@ -137,14 +148,16 @@ module ActionCableNotifications
|
|
137
148
|
cache: false
|
138
149
|
}.merge(options)
|
139
150
|
|
140
|
-
packet = packet.as_json.deep_symbolize_keys
|
151
|
+
packet = packet.as_json.deep_symbolize_keys
|
141
152
|
|
142
|
-
if options
|
143
|
-
if
|
153
|
+
if validate_packet(packet, options)
|
154
|
+
if options[:cache]==true
|
155
|
+
if update_cache(packet)
|
156
|
+
transmit packet
|
157
|
+
end
|
158
|
+
else
|
144
159
|
transmit packet
|
145
160
|
end
|
146
|
-
else
|
147
|
-
transmit packet
|
148
161
|
end
|
149
162
|
end
|
150
163
|
|
@@ -21,12 +21,13 @@ module ActionCableNotifications
|
|
21
21
|
to_a() rescue []
|
22
22
|
|
23
23
|
response = {
|
24
|
-
|
24
|
+
publication: data[:publication],
|
25
25
|
msg: 'upsert_many',
|
26
26
|
data: results
|
27
27
|
}
|
28
28
|
rescue Exception => e
|
29
29
|
response = {
|
30
|
+
publication: data[:publication],
|
30
31
|
collection: data[:model].model_name.collection,
|
31
32
|
msg: 'error',
|
32
33
|
command: data[:command],
|
@@ -35,7 +36,7 @@ module ActionCableNotifications
|
|
35
36
|
end
|
36
37
|
|
37
38
|
# Send data to the client
|
38
|
-
transmit_packet response
|
39
|
+
transmit_packet response, data[:options]
|
39
40
|
end
|
40
41
|
|
41
42
|
#
|
@@ -1,7 +1,51 @@
|
|
1
|
+
require 'action_cable_notifications/hash_db.rb'
|
2
|
+
|
1
3
|
module ActionCableNotifications
|
2
4
|
module Channel
|
3
5
|
module Cache
|
4
6
|
|
7
|
+
def initialize(*args)
|
8
|
+
super
|
9
|
+
@cache = HashDB::Base.new()
|
10
|
+
end
|
11
|
+
|
12
|
+
#
|
13
|
+
# Validates packet before transmitting the message
|
14
|
+
#
|
15
|
+
# @param [Hash] packet Packet to be transmitted
|
16
|
+
# @param [Hash] options Channels options used to validate the packet
|
17
|
+
#
|
18
|
+
# @return [Boolean] <description>
|
19
|
+
#
|
20
|
+
def validate_packet(packet, options = {})
|
21
|
+
options = {
|
22
|
+
}.merge(options)
|
23
|
+
|
24
|
+
if packet[:msg].in? ['upsert_many', 'create', 'update', 'destroy']
|
25
|
+
if packet[:msg].in? ['upsert_many']
|
26
|
+
data = packet[:data]
|
27
|
+
else
|
28
|
+
data = [(packet[:data] || {}).merge({id: packet[:id]})]
|
29
|
+
end
|
30
|
+
|
31
|
+
packet_validator = HashDB::Base.new(data)
|
32
|
+
data = packet_validator.scoped_collection(options[:scope]).data
|
33
|
+
if data.present?
|
34
|
+
if packet[:msg].in? ['upsert_many']
|
35
|
+
packet[:data] = data
|
36
|
+
else
|
37
|
+
packet[:data] = data.first
|
38
|
+
end
|
39
|
+
true
|
40
|
+
else
|
41
|
+
false
|
42
|
+
end
|
43
|
+
else
|
44
|
+
true
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
5
49
|
#
|
6
50
|
# Updates server side cache of client side collections
|
7
51
|
# XXX compute cache diff before sending to clients
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module HashDB
|
2
|
+
class Base
|
3
|
+
|
4
|
+
def initialize(data=nil)
|
5
|
+
if data.present?
|
6
|
+
@data = Array(data)
|
7
|
+
else
|
8
|
+
@data = []
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def data
|
13
|
+
@data
|
14
|
+
end
|
15
|
+
|
16
|
+
def data=(data)
|
17
|
+
@data = data || []
|
18
|
+
end
|
19
|
+
|
20
|
+
def wrap(data)
|
21
|
+
HashDB::Base.new(data)
|
22
|
+
end
|
23
|
+
|
24
|
+
private :wrap
|
25
|
+
|
26
|
+
def all(options={})
|
27
|
+
if options.has_key?(:conditions)
|
28
|
+
where(options[:conditions])
|
29
|
+
else
|
30
|
+
wrap(@data ||= [])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def count
|
35
|
+
all.length
|
36
|
+
end
|
37
|
+
|
38
|
+
def where(options)
|
39
|
+
return @data if options.blank?
|
40
|
+
|
41
|
+
data = (@data || []).select do |record|
|
42
|
+
match_options?(record, options)
|
43
|
+
end
|
44
|
+
|
45
|
+
wrap(data)
|
46
|
+
end
|
47
|
+
|
48
|
+
def match_options?(record, options)
|
49
|
+
options.all? do |col, match|
|
50
|
+
if [Array, Range].include?(match.class)
|
51
|
+
match.include?(record[col])
|
52
|
+
else
|
53
|
+
record[col] == match
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
private :match_options?
|
59
|
+
|
60
|
+
def scoped_collection ( scope = :all )
|
61
|
+
scope = scope.to_a if scope.is_a? Hash
|
62
|
+
Array(scope).inject(self) do |o, a|
|
63
|
+
o.try(*a)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def select( fields=nil )
|
68
|
+
if fields.present?
|
69
|
+
wrap(@data.map{|v| v.slice(*(Array(fields).map(&:to_sym)))})
|
70
|
+
else
|
71
|
+
all
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def limit( count=nil )
|
76
|
+
if count.present? and count>0
|
77
|
+
wrap(@data.slice(0,count))
|
78
|
+
else
|
79
|
+
all
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def delete_all
|
84
|
+
@data = []
|
85
|
+
end
|
86
|
+
|
87
|
+
def first
|
88
|
+
@data.first
|
89
|
+
end
|
90
|
+
|
91
|
+
def last
|
92
|
+
@data.last
|
93
|
+
end
|
94
|
+
|
95
|
+
def find(id, * args)
|
96
|
+
case id
|
97
|
+
when nil
|
98
|
+
nil
|
99
|
+
when :all
|
100
|
+
all
|
101
|
+
when :first
|
102
|
+
all(*args).first
|
103
|
+
when Array
|
104
|
+
id.map { |i| find(i) }
|
105
|
+
else
|
106
|
+
where({id: id})
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
@@ -4,8 +4,8 @@ module ActionCableNotifications
|
|
4
4
|
|
5
5
|
included do
|
6
6
|
# Action cable notification options storage
|
7
|
-
class_attribute :
|
8
|
-
self.
|
7
|
+
class_attribute :ChannelPublications
|
8
|
+
self.ChannelPublications = {}
|
9
9
|
|
10
10
|
# Register Callbacks
|
11
11
|
before_update :prepare_update
|
@@ -19,19 +19,19 @@ module ActionCableNotifications
|
|
19
19
|
#
|
20
20
|
# Sets or removes notificacions options for Active Record model
|
21
21
|
#
|
22
|
-
# @param [sym]
|
22
|
+
# @param [sym] publication Topic name to broadcast in
|
23
23
|
# @param [hash] options Hash containing notification options
|
24
24
|
#
|
25
|
-
def broadcast_notifications_from (
|
25
|
+
def broadcast_notifications_from ( publication, options = {} )
|
26
26
|
# Default options
|
27
27
|
options = {
|
28
28
|
actions: [:create, :update, :destroy],
|
29
|
-
track_scope_changes:
|
29
|
+
track_scope_changes: false,
|
30
30
|
scope: :all, # Default collection scope
|
31
31
|
records: []
|
32
32
|
}.merge(options)
|
33
33
|
|
34
|
-
self.
|
34
|
+
self.ChannelPublications[publication.to_s] = options
|
35
35
|
end
|
36
36
|
|
37
37
|
#
|
@@ -50,19 +50,17 @@ module ActionCableNotifications
|
|
50
50
|
#
|
51
51
|
# Retrieves initial values to be sent to clients upon subscription
|
52
52
|
#
|
53
|
-
# @param [Sym]
|
53
|
+
# @param [Sym] publication Name of publication stream
|
54
54
|
#
|
55
55
|
# @return [Hash] Hash containing the results in the following format:
|
56
56
|
# {
|
57
|
-
# collection: self.model_name.collection,
|
58
57
|
# msg: 'add_collection',
|
59
58
|
# data: self.scoped_collection(options[:scope])
|
60
59
|
# }
|
61
|
-
def notify_initial (
|
62
|
-
options = self.
|
60
|
+
def notify_initial ( publication )
|
61
|
+
options = self.ChannelPublications[publication.to_s]
|
63
62
|
if options.present?
|
64
63
|
{
|
65
|
-
collection: self.model_name.collection,
|
66
64
|
msg: 'upsert_many',
|
67
65
|
data: self.scoped_collection(options[:scope])
|
68
66
|
}
|
@@ -74,12 +72,11 @@ module ActionCableNotifications
|
|
74
72
|
# Broadcast notifications when a new record is created
|
75
73
|
#
|
76
74
|
def notify_create
|
77
|
-
self.
|
75
|
+
self.ChannelPublications.each do |publication, options|
|
78
76
|
if options[:actions].include? :create
|
79
77
|
# Checks if record is within scope before broadcasting
|
80
78
|
if options[:scope]==:all or self.class.scoped_collection(options[:scope]).where(id: self.id).present?
|
81
|
-
ActionCable.server.broadcast
|
82
|
-
collection: self.model_name.collection,
|
79
|
+
ActionCable.server.broadcast publication,
|
83
80
|
msg: 'create',
|
84
81
|
id: self.id,
|
85
82
|
data: self
|
@@ -89,7 +86,7 @@ module ActionCableNotifications
|
|
89
86
|
end
|
90
87
|
|
91
88
|
def prepare_update
|
92
|
-
self.
|
89
|
+
self.ChannelPublications.each do |publication, options|
|
93
90
|
if options[:actions].include? :update
|
94
91
|
if options[:scope]==:all
|
95
92
|
options[:records].push self
|
@@ -108,9 +105,16 @@ module ActionCableNotifications
|
|
108
105
|
# if they are within configured scope
|
109
106
|
#
|
110
107
|
def notify_update
|
108
|
+
# Get model changes
|
109
|
+
if self.respond_to?(:saved_changes) # For Rails >= 5.1
|
110
|
+
changes = self.saved_changes.transform_values(&:second)
|
111
|
+
else # For Rails < 5.1
|
112
|
+
changes = self.changes.transform_values(&:second)
|
113
|
+
end
|
114
|
+
|
111
115
|
# Checks if there are changes in the model
|
112
|
-
if !
|
113
|
-
self.
|
116
|
+
if !changes.empty?
|
117
|
+
self.ChannelPublications.each do |publication, options|
|
114
118
|
if options[:actions].include? :update
|
115
119
|
# Checks if previous record was within scope
|
116
120
|
record = options[:records].detect{|r| r.id==self.id}
|
@@ -136,24 +140,24 @@ module ActionCableNotifications
|
|
136
140
|
|
137
141
|
# Broadcasts notifications about model changes
|
138
142
|
if is_in_scope
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
if record.respond_to?(k)
|
143
|
-
changes[k] = v[1]
|
144
|
-
end
|
145
|
-
end
|
143
|
+
if was_in_scope
|
144
|
+
# Get model changes and applies them to the scoped collection record
|
145
|
+
changes.select!{|k,v| record.respond_to?(k)}
|
146
146
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
147
|
+
if !changes.empty?
|
148
|
+
ActionCable.server.broadcast publication,
|
149
|
+
msg: 'update',
|
150
|
+
id: self.id,
|
151
|
+
data: changes
|
152
|
+
end
|
153
|
+
else
|
154
|
+
ActionCable.server.broadcast publication,
|
155
|
+
msg: 'create',
|
156
|
+
id: record.id,
|
157
|
+
data: record
|
153
158
|
end
|
154
159
|
elsif was_in_scope # checks if needs to delete the record if its no longer in scope
|
155
|
-
ActionCable.server.broadcast
|
156
|
-
collection: self.model_name.collection,
|
160
|
+
ActionCable.server.broadcast publication,
|
157
161
|
msg: 'destroy',
|
158
162
|
id: self.id
|
159
163
|
end
|
@@ -166,12 +170,11 @@ module ActionCableNotifications
|
|
166
170
|
# Broadcast notifications when a record is destroyed.
|
167
171
|
#
|
168
172
|
def notify_destroy
|
169
|
-
self.
|
173
|
+
self.ChannelPublications.each do |publication, options|
|
170
174
|
if options[:scope]==:all or options[:actions].include? :destroy
|
171
175
|
# Checks if record is within scope before broadcasting
|
172
176
|
if options[:scope]==:all or self.class.scoped_collection(options[:scope]).where(id: self.id).present?
|
173
|
-
ActionCable.server.broadcast
|
174
|
-
collection: self.model_name.collection,
|
177
|
+
ActionCable.server.broadcast publication,
|
175
178
|
msg: 'destroy',
|
176
179
|
id: self.id
|
177
180
|
end
|
metadata
CHANGED
@@ -1,22 +1,19 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: action_cable_notifications
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.30
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ByS Sistemas de Control
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-05-
|
11
|
+
date: 2017-05-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: 5.0.0
|
20
17
|
- - ">="
|
21
18
|
- !ruby/object:Gem::Version
|
22
19
|
version: 5.0.0.1
|
@@ -24,9 +21,6 @@ dependencies:
|
|
24
21
|
prerelease: false
|
25
22
|
version_requirements: !ruby/object:Gem::Requirement
|
26
23
|
requirements:
|
27
|
-
- - "~>"
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: 5.0.0
|
30
24
|
- - ">="
|
31
25
|
- !ruby/object:Gem::Version
|
32
26
|
version: 5.0.0.1
|
@@ -34,14 +28,14 @@ dependencies:
|
|
34
28
|
name: lodash-rails
|
35
29
|
requirement: !ruby/object:Gem::Requirement
|
36
30
|
requirements:
|
37
|
-
- - "
|
31
|
+
- - ">="
|
38
32
|
- !ruby/object:Gem::Version
|
39
33
|
version: 4.15.0
|
40
34
|
type: :runtime
|
41
35
|
prerelease: false
|
42
36
|
version_requirements: !ruby/object:Gem::Requirement
|
43
37
|
requirements:
|
44
|
-
- - "
|
38
|
+
- - ">="
|
45
39
|
- !ruby/object:Gem::Version
|
46
40
|
version: 4.15.0
|
47
41
|
- !ruby/object:Gem::Dependency
|
@@ -132,6 +126,7 @@ files:
|
|
132
126
|
- lib/action_cable_notifications/channel_actions.rb
|
133
127
|
- lib/action_cable_notifications/channel_cache.rb
|
134
128
|
- lib/action_cable_notifications/engine.rb
|
129
|
+
- lib/action_cable_notifications/hash_db.rb
|
135
130
|
- lib/action_cable_notifications/model.rb
|
136
131
|
- lib/action_cable_notifications/version.rb
|
137
132
|
- lib/tasks/action_cable_notifications_tasks.rake
|