action_cable_notifications 0.1.5 → 0.1.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 77099f72f8abc9a8cdddad94a14066bacf6ed237
4
- data.tar.gz: 7912095ef91683daa7a35a5ae951b06674d57ee7
3
+ metadata.gz: af4258aa0ac4cfba0b3f42a7aab2db6d91daf7a3
4
+ data.tar.gz: b2493f00d932a61c9ea7ecaabad17fa43bb25dc0
5
5
  SHA512:
6
- metadata.gz: 1dc22ba6426f9b2f06ef710e6908bb97eac861c6fd0d6810cf887e21814d1531621fcde8ab6a12ccdd75a2a0152f069100ad5b3d75d977cd221db148197c6e7c
7
- data.tar.gz: d079cacae3eb059499f1f008928dd677be4aefbc873420b647a7db588b47f13d6d24fc506bae64395363b292f9fcde29e1d30a6a16f9dd20463ca11f367ac302
6
+ metadata.gz: cb152248983ea3678b5b2933046a8604cd23ff16de46191709117fafa687a24272cc2bb7f5f6ab3e737ef22f9cd96553e1f21a34ea64c484a0f74a0e41e33029
7
+ data.tar.gz: 6f19980552466b17e0ab2cdf6424cf86e620e6afdff01c71bb71a9fd6d815acd4d7108580dc59fff69d540620baa38f36561dd0743cf9e136865e715ea53fe99
data/README.md CHANGED
@@ -1,30 +1,12 @@
1
1
  # ActionCableNotifications
2
2
  [![Gem Version](https://badge.fury.io/rb/action_cable_notifications.svg)](https://badge.fury.io/rb/action_cable_notifications)
3
3
 
4
- This gem is under develoment and is not ready for production usage.
4
+ **This gem is being developed as part of an internal proyect. It's constantly changing and is not ready for production usage. Use at your own risk!!**
5
5
 
6
6
  ## Usage
7
- How to use my plugin.
8
7
 
9
- ## Installation
10
- Add this line to your application's Gemfile:
11
-
12
- ```ruby
13
- gem 'action_cable_notifications'
14
- ```
15
-
16
- And then execute:
17
- ```bash
18
- $ bundle
19
- ```
20
-
21
- Or install it yourself as:
22
- ```bash
23
- $ gem install action_cable_notifications
24
- ```
25
-
26
- ## Usage
27
- Create a new channel (`rails g cahnnel Test`) or modify existing one including `ActionCableNotifications::Streams` module.
8
+ ### Server side
9
+ On **server-side**, create a new channel (`rails g cahnnel Test`) or modify existing one including `ActionCableNotifications::Streams` module.
28
10
 
29
11
  ```ruby
30
12
  class TestChannel < ApplicationCable::Channel
@@ -32,7 +14,7 @@ class TestChannel < ApplicationCable::Channel
32
14
  include ActionCableNotifications::Streams
33
15
 
34
16
  def subscribed
35
- stream_notifications_for model, include_initial: true, scope: [:all, [:limit, 5], [:order, :id]]
17
+ stream_notifications_for Users, include_initial: true, scope: [:all, [:limit, 5], [:order, :id]]
36
18
  end
37
19
 
38
20
  def unsubscribed
@@ -41,7 +23,7 @@ class TestChannel < ApplicationCable::Channel
41
23
  end
42
24
  ```
43
25
 
44
- Method stream_notifications_for receives the following parameters:
26
+ Method `stream_notifications_for` receives the following parameters:
45
27
 
46
28
  ```ruby
47
29
  stream_notifications_for(model, options = {}, &block)
@@ -63,8 +45,83 @@ stream_notifications_for(model, options = {}, &block)
63
45
  ```
64
46
  * block: **(Proc)** - Same as options[:callback]
65
47
 
48
+ ### Client side
49
+ On **client-side**, use action_cable subscriptions as stated in the documentation. Received data will have the following format:
50
+
51
+ #### Initial values for collection
52
+ ```javascript
53
+ {
54
+ collection: 'users',
55
+ msg: 'add_collection',
56
+ data: [
57
+ {
58
+ id: 1,
59
+ username: 'username 1',
60
+ color: 'red'
61
+ },
62
+ {
63
+ id: 2,
64
+ username: 'username 2',
65
+ color: 'green'
66
+ ]
67
+ }
68
+ ```
69
+
70
+ #### Create event
71
+ ```javascript
72
+ {
73
+ collection: 'users',
74
+ msg: 'create',
75
+ id: 3,
76
+ data: {
77
+ id: 3,
78
+ username: 'username 3'
79
+ color: 'blue'
80
+ }
81
+ }
82
+ ```
83
+
84
+ #### Update event
85
+ Update event will only transmit changed fields for the model.
86
+ ```javascript
87
+ {
88
+ collection: 'users',
89
+ msg: 'update',
90
+ id: 2,
91
+ data: {
92
+ color: 'light blue'
93
+ }
94
+ }
95
+ ```
96
+
97
+ #### Destroy event
98
+ ```javascript
99
+ {
100
+ collection: 'users',
101
+ msg: 'destroy',
102
+ id: 2
103
+ }
104
+ ```
105
+
106
+ ## Installation
107
+ Add this line to your application's Gemfile:
108
+
109
+ ```ruby
110
+ gem 'action_cable_notifications'
111
+ ```
112
+
113
+ And then execute:
114
+ ```bash
115
+ $ bundle
116
+ ```
117
+
118
+ Or install it yourself as:
119
+ ```bash
120
+ $ gem install action_cable_notifications
121
+ ```
122
+
66
123
  ## Contributing
67
- Contribution directions go here.
124
+ Contributions are welcome. We will be happy to receive issues, comments and pull-request to make this gem better.
68
125
 
69
126
  ## License
70
127
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -3,61 +3,95 @@ module ActionCableNotifications
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- # Options
6
+ # Action cable notification options storage
7
7
  class_attribute :ActionCableNotificationsOptions
8
8
  self.ActionCableNotificationsOptions = {}
9
9
 
10
+ # Register Callbacks
10
11
  after_update :notify_update
11
12
  after_create :notify_create
12
- after_destroy :notify_destroy
13
+ before_destroy :notify_destroy
13
14
  end
14
15
 
15
16
  module ClassMethods
16
- # Options setter
17
- def action_cable_notification_options= ( broadcasting, options = nil )
17
+
18
+ #
19
+ # Sets or removes notificacions options for Active Record model
20
+ #
21
+ # @param [sym] broadcasting Topic name to broadcast in
22
+ # @param [hash] options Hash containing notification options
23
+ #
24
+ def broadcast_notifications_from ( broadcasting, options = nil )
18
25
  if options.present?
26
+ # Default options
27
+ options = {
28
+ actions: [:create, :update, :destroy],
29
+ scope: :all # Default collection scope
30
+ }.merge(options)
31
+
19
32
  self.ActionCableNotificationsOptions[broadcasting.to_sym] = options
20
33
  else
21
34
  self.ActionCableNotificationsOptions.except! broadcasting.to_sym
22
35
  end
23
36
  end
24
37
 
25
- # Options getter
26
- def action_cable_notification_options ( broadcasting )
27
- if broadcasting.present?
28
- self.ActionCableNotificationsOptions[broadcasting.to_sym]
29
- else
30
- self.ActionCableNotificationsOptions
31
- end
32
- end
33
-
34
- def scoped_collection ( scope )
35
- Array(Array(scope).inject(self) {|o, a| o.try(*a)})
38
+ #
39
+ # Returns collection scoped as specified in parameters.
40
+ #
41
+ # @param [Array] scope Contains the scopes to be applied. For
42
+ # example: [[:limit, 5], [:order, :id]]
43
+ #
44
+ # @return [ActiveRecordRelation] Results fetched from the database
45
+ #
46
+ def scoped_collection ( scope=:all )
47
+ Array(scope).inject(self) {|o, a| o.try(*a)}
36
48
  end
37
49
 
50
+ #
51
+ # Retrieves initial values to be sent to clients upon subscription
52
+ #
53
+ # @param [Sym] broadcasting Name of broadcasting stream
54
+ #
55
+ # @return [Hash] Hash containing the results in the following format:
56
+ # {
57
+ # collection: self.model_name.collection,
58
+ # msg: 'add_collection',
59
+ # data: self.scoped_collection(options[:scope])
60
+ # }
38
61
  def notify_initial ( broadcasting )
39
- options = self.action_cable_notification_options( broadcasting )
40
- {
41
- collection: self.model_name.collection,
42
- msg: 'add_collection',
43
- data: self.scoped_collection(options[:scope])
44
- }
62
+ options = self.ActionCableNotificationsOptions[broadcasting.to_sym]
63
+ if options.present?
64
+ {
65
+ collection: self.model_name.collection,
66
+ msg: 'add_collection',
67
+ data: self.scoped_collection(options[:scope])
68
+ }
69
+ end
45
70
  end
46
71
  end
47
72
 
73
+ #
74
+ # Broadcast notifications when a new record is created
75
+ #
48
76
  def notify_create
49
77
  self.ActionCableNotificationsOptions.each do |broadcasting, options|
50
- # Checks if record is within scope before broadcasting
51
- if self.class.scoped_collection(options[:scope]).include? self
52
- ActionCable.server.broadcast broadcasting,
53
- collection: self.model_name.collection,
54
- msg: 'create',
55
- id: self.id,
56
- data: self
78
+ if options[:actions].include? :create
79
+ # Checks if record is within scope before broadcasting
80
+ if self.class.scoped_collection(options[:scope]).where(id: self.id)
81
+ ActionCable.server.broadcast broadcasting,
82
+ collection: self.model_name.collection,
83
+ msg: 'added',
84
+ id: self.id,
85
+ data: self
86
+ end
57
87
  end
58
88
  end
59
89
  end
60
90
 
91
+ #
92
+ # Broadcast notifications when a record is updated. Only changed
93
+ # field will be sent.
94
+ #
61
95
  def notify_update
62
96
  changes = {}
63
97
  self.changes.each do |k,v|
@@ -65,25 +99,38 @@ module ActionCableNotifications
65
99
  end
66
100
 
67
101
  self.ActionCableNotificationsOptions.each do |broadcasting, options|
68
- # Checks if record is within scope before broadcasting
69
- if self.class.scoped_collection(options[:scope]).include? self
70
- ActionCable.server.broadcast broadcasting,
71
- collection: self.model_name.collection,
72
- msg: 'update',
73
- id: self.id,
74
- data: changes
102
+ if options[:actions].include? :update
103
+ # Checks if record is within scope before broadcasting
104
+ if self.class.scoped_collection(options[:scope]).where(id: self.id)
105
+ # XXX: Performance required. For small data sets this should be
106
+ # fast enough, but for large data sets this could be slow. As
107
+ # clients should have a limited subset of the dataset loaded at a
108
+ # time, caching the results already sent to clients in server memory
109
+ # should not have a big impact in memory usage but can improve
110
+ # performance for large data sets where only a sub
111
+ ActionCable.server.broadcast broadcasting,
112
+ collection: self.model_name.collection,
113
+ msg: 'changed',
114
+ id: self.id,
115
+ data: changes
116
+ end
75
117
  end
76
118
  end
77
119
  end
78
120
 
121
+ #
122
+ # Broadcast notifications when a record is destroyed.
123
+ #
79
124
  def notify_destroy
80
125
  self.ActionCableNotificationsOptions.each do |broadcasting, options|
81
- # Checks if record is within scope before broadcasting
82
- if self.class.scoped_collection(options[:scope]).include? self
83
- ActionCable.server.broadcast broadcasting,
84
- collection: self.model_name.collection,
85
- msg: 'destroy',
86
- id: self.id
126
+ if options[:actions].include? :destroy
127
+ # Checks if record is within scope before broadcasting
128
+ if self.class.scoped_collection(options[:scope]).where(id: self.id)
129
+ ActionCable.server.broadcast broadcasting,
130
+ collection: self.model_name.collection,
131
+ msg: 'removed',
132
+ id: self.id
133
+ end
87
134
  end
88
135
  end
89
136
  end
@@ -9,10 +9,8 @@ module ActionCableNotifications
9
9
  private
10
10
 
11
11
  def stream_notifications_for(model, options = {}, &block)
12
- @model = model
13
-
14
12
  # Default options
15
- @options = {
13
+ options = {
16
14
  actions: [:create, :update, :destroy],
17
15
  broadcasting: model.model_name.collection,
18
16
  callback: nil,
@@ -23,29 +21,29 @@ module ActionCableNotifications
23
21
  }.merge(options)
24
22
 
25
23
  # Checks if model already includes notification callbacks
26
- if !@model.respond_to? :ActionCableNotificationsOptions
27
- @model.send('include', ActionCableNotifications::Callbacks)
24
+ if !model.respond_to? :ActionCableNotificationsOptions
25
+ model.send('include', ActionCableNotifications::Callbacks)
26
+ # Set specified options on model
28
27
  end
29
28
 
30
- # Set specified options on model
31
- @model.send('action_cable_notification_options=', @options[:broadcasting], @options)
29
+ # Sets broadcast options if they are not already present in the model
30
+ if not model.ActionCableNotificationsOptions.key? options[:broadcasting]
31
+ model.broadcast_notifications_from options[:broadcasting], options
32
+ end
32
33
 
33
34
  # Start streaming
34
- stream_from(@options[:broadcasting], options[:callback] || block, @options.slice(:coder))
35
+ stream_from(options[:broadcasting], options[:callback] || block, options.slice(:coder))
35
36
 
36
37
  # Transmit initial state if required
37
- if @options[:include_initial]
38
+ if options[:include_initial]
38
39
  # XXX: Check if data should be transmitted
39
- transmit @model.notify_initial @options[:broadcasting]
40
+ transmit model.notify_initial options[:broadcasting]
40
41
  end
41
42
 
42
43
  end
43
44
 
44
45
  def unsubscribed
45
46
  stop_all_streams
46
-
47
- # Unset options for this channel on model
48
- @model.send('action_cable_notification_options=', @options[:broadcasting], nil)
49
47
  end
50
48
 
51
49
  end
@@ -1,3 +1,3 @@
1
1
  module ActionCableNotifications
2
- VERSION = '0.1.5'
2
+ VERSION = '0.1.6'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: action_cable_notifications
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
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: 2016-08-30 00:00:00.000000000 Z
11
+ date: 2016-09-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails