actioncable 7.1.5.1 → 7.2.2.1

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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +30 -138
  3. data/app/assets/javascripts/action_cable.js +3 -3
  4. data/app/assets/javascripts/actioncable.esm.js +3 -3
  5. data/app/assets/javascripts/actioncable.js +3 -3
  6. data/lib/action_cable/channel/base.rb +98 -86
  7. data/lib/action_cable/channel/broadcasting.rb +25 -18
  8. data/lib/action_cable/channel/callbacks.rb +27 -25
  9. data/lib/action_cable/channel/naming.rb +9 -8
  10. data/lib/action_cable/channel/periodic_timers.rb +7 -7
  11. data/lib/action_cable/channel/streams.rb +77 -64
  12. data/lib/action_cable/channel/test_case.rb +112 -86
  13. data/lib/action_cable/connection/authorization.rb +4 -1
  14. data/lib/action_cable/connection/base.rb +53 -38
  15. data/lib/action_cable/connection/callbacks.rb +20 -18
  16. data/lib/action_cable/connection/client_socket.rb +3 -1
  17. data/lib/action_cable/connection/identification.rb +9 -5
  18. data/lib/action_cable/connection/internal_channel.rb +5 -2
  19. data/lib/action_cable/connection/message_buffer.rb +4 -1
  20. data/lib/action_cable/connection/stream.rb +2 -0
  21. data/lib/action_cable/connection/stream_event_loop.rb +4 -3
  22. data/lib/action_cable/connection/subscriptions.rb +6 -3
  23. data/lib/action_cable/connection/tagged_logger_proxy.rb +7 -4
  24. data/lib/action_cable/connection/test_case.rb +66 -56
  25. data/lib/action_cable/connection/web_socket.rb +10 -8
  26. data/lib/action_cable/deprecator.rb +2 -0
  27. data/lib/action_cable/engine.rb +5 -3
  28. data/lib/action_cable/gem_version.rb +5 -3
  29. data/lib/action_cable/helpers/action_cable_helper.rb +21 -19
  30. data/lib/action_cable/remote_connections.rb +19 -16
  31. data/lib/action_cable/server/base.rb +27 -15
  32. data/lib/action_cable/server/broadcasting.rb +23 -17
  33. data/lib/action_cable/server/configuration.rb +17 -14
  34. data/lib/action_cable/server/connections.rb +11 -5
  35. data/lib/action_cable/server/worker/active_record_connection_management.rb +2 -0
  36. data/lib/action_cable/server/worker.rb +4 -2
  37. data/lib/action_cable/subscription_adapter/async.rb +2 -0
  38. data/lib/action_cable/subscription_adapter/base.rb +2 -0
  39. data/lib/action_cable/subscription_adapter/channel_prefix.rb +2 -0
  40. data/lib/action_cable/subscription_adapter/inline.rb +2 -0
  41. data/lib/action_cable/subscription_adapter/postgresql.rb +4 -2
  42. data/lib/action_cable/subscription_adapter/redis.rb +5 -2
  43. data/lib/action_cable/subscription_adapter/subscriber_map.rb +2 -0
  44. data/lib/action_cable/subscription_adapter/test.rb +8 -5
  45. data/lib/action_cable/test_case.rb +2 -0
  46. data/lib/action_cable/test_helper.rb +51 -48
  47. data/lib/action_cable/version.rb +3 -1
  48. data/lib/action_cable.rb +12 -6
  49. data/lib/rails/generators/channel/channel_generator.rb +4 -2
  50. data/lib/rails/generators/test_unit/channel_generator.rb +2 -0
  51. metadata +11 -11
  52. /data/lib/rails/generators/channel/templates/application_cable/{channel.rb → channel.rb.tt} +0 -0
  53. /data/lib/rails/generators/channel/templates/application_cable/{connection.rb → connection.rb.tt} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: edd9d86e9fbca1d2b24d81d798d1a50eac2fe0f33f5b9a6b623c3a0e8d02ac7d
4
- data.tar.gz: bd9c7fca8f92dd7e0b6a6dc30e8a2c8ba221baf08da2a1ca9b56ade8e27505f8
3
+ metadata.gz: 720238323d1411f0913bcc9b65ac89d955c4fc4e708bbab5b5dd1c0c47c4cf00
4
+ data.tar.gz: 10a5cd05102adeda05b151a39c40183bc55c2c55c2c63dca5a13d642fcf49f58
5
5
  SHA512:
6
- metadata.gz: 78049f1d0b8779d8202b3ce9ae6feee445b6200065c5eb78103a662d18a2015f890ff6662bb9df1bf5d8da34a03f7a5bb7af81709f13851b13894ba2432d3a1f
7
- data.tar.gz: e403b191bafc0f75694adbb8727b7be7f17acb855314ddffe5a860a57c17a471c62ce7ebcb4526af815e3ffe98f24218197f2216533f0341063fe6f8ab664b9a
6
+ metadata.gz: '0639a73b1efc8078fe167814911d5694e76781f618ac7fe5bb34ae8448ab495b60f598a76c6a0e8d7c9f45d9674d19564ad14eaae0ccaaf1f75b441d1318d7c8'
7
+ data.tar.gz: 4988a92b2c683bc86c28d60be1d2f92d1efe36bc5d33f814da55ac7328af60597fb0313321aa663b6d5632ecd565661725d12bf1238fa48a153b18d538e6e08e
data/CHANGELOG.md CHANGED
@@ -1,176 +1,68 @@
1
- ## Rails 7.1.5.1 (December 10, 2024) ##
1
+ ## Rails 7.2.2.1 (December 10, 2024) ##
2
2
 
3
3
  * No changes.
4
4
 
5
5
 
6
- ## Rails 7.1.5 (October 30, 2024) ##
6
+ ## Rails 7.2.2 (October 30, 2024) ##
7
7
 
8
8
  * No changes.
9
9
 
10
10
 
11
- ## Rails 7.1.4.2 (October 23, 2024) ##
11
+ ## Rails 7.2.1.2 (October 23, 2024) ##
12
12
 
13
13
  * No changes.
14
14
 
15
15
 
16
- ## Rails 7.1.4.1 (October 15, 2024) ##
16
+ ## Rails 7.2.1.1 (October 15, 2024) ##
17
17
 
18
18
  * No changes.
19
19
 
20
20
 
21
- ## Rails 7.1.4 (August 22, 2024) ##
21
+ ## Rails 7.2.1 (August 22, 2024) ##
22
22
 
23
23
  * No changes.
24
24
 
25
25
 
26
- ## Rails 7.1.3.4 (June 04, 2024) ##
26
+ ## Rails 7.2.0 (August 09, 2024) ##
27
27
 
28
- * No changes.
29
-
30
-
31
- ## Rails 7.1.3.3 (May 16, 2024) ##
32
-
33
- * No changes.
34
-
35
-
36
- ## Rails 7.1.3.2 (February 21, 2024) ##
37
-
38
- * No changes.
39
-
40
-
41
- ## Rails 7.1.3.1 (February 21, 2024) ##
42
-
43
- * No changes.
44
-
45
-
46
- ## Rails 7.1.3 (January 16, 2024) ##
47
-
48
- * No changes.
49
-
50
-
51
- ## Rails 7.1.2 (November 10, 2023) ##
52
-
53
- * No changes.
54
-
55
-
56
- ## Rails 7.1.1 (October 11, 2023) ##
57
-
58
- * No changes.
59
-
60
-
61
- ## Rails 7.1.0 (October 05, 2023) ##
62
-
63
- * No changes.
64
-
65
-
66
- ## Rails 7.1.0.rc2 (October 01, 2023) ##
67
-
68
- * No changes.
69
-
70
-
71
- ## Rails 7.1.0.rc1 (September 27, 2023) ##
72
-
73
- * No changes.
74
-
75
-
76
- ## Rails 7.1.0.beta1 (September 13, 2023) ##
77
-
78
- * Add a `@server` instance variable referencing the `ActionCable.server`
79
- singleton to `ActionCable::Channel::ConnectionStub`
28
+ * Bring `ActionCable::Connection::TestCookieJar` in alignment with `ActionDispatch::Cookies::CookieJar` in regards to setting the cookie value.
80
29
 
81
- This lets us delegate the `pubsub` and `config` method calls
82
- to the server. This fixes `NoMethodError` errors when testing
83
- channel logic that call `pubsub` (e.g. `stop_stream_for`).
84
-
85
- *Julian Foo*
86
-
87
- * Added `health_check_path` and `health_check_application` config to
88
- mount a given health check rack app on a given path.
89
- Useful when mounting Action Cable standalone.
90
-
91
- *Joé Dupuis*
92
-
93
- * Introduce the `capture_broadcasts` test helper.
94
-
95
- Returns all messages broadcast in a block.
30
+ Before:
96
31
 
97
32
  ```ruby
98
- messages = capture_broadcasts("test") do
99
- ActionCable.server.broadcast "test", { message: "one" }
100
- ActionCable.server.broadcast "test", { message: "two" }
101
- end
102
- assert_equal 2, messages.length
103
- assert_equal({ "message" => "one" }, messages.first)
104
- assert_equal({ "message" => "two" }, messages.last)
33
+ cookies[:foo] = { value: "bar" }
34
+ puts cookies[:foo] # => { value: "bar" }
105
35
  ```
106
36
 
107
- *Alex Ghiculescu*
108
-
109
- * Display broadcasted messages on error message when using `assert_broadcast_on`
110
-
111
- *Stéphane Robino*
112
-
113
- * The Action Cable client now supports subprotocols to allow passing arbitrary data
114
- to the server.
37
+ After:
115
38
 
116
- ```js
117
- const consumer = ActionCable.createConsumer()
118
-
119
- consumer.addSubProtocol('custom-protocol')
120
-
121
- consumer.connect()
39
+ ```ruby
40
+ cookies[:foo] = { value: "bar" }
41
+ puts cookies[:foo] # => "bar"
122
42
  ```
123
43
 
124
- See also:
125
-
126
- * https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers#subprotocols
44
+ *Justin Ko*
127
45
 
128
- *Guillaume Hain*
46
+ * Record ping on every Action Cable message.
129
47
 
130
- * Redis pub/sub adapter now automatically reconnects when Redis connection is lost.
48
+ Previously only `ping` and `welcome` message types were keeping the connection active.
49
+ Now every Action Cable message updates the `pingedAt` value, preventing the connection
50
+ from being marked as stale.
131
51
 
132
- *Vladimir Dementyev*
52
+ *yauhenininjia*
133
53
 
134
- * The `connected()` callback can now take a `{reconnected}` parameter to differentiate
135
- connections from reconnections.
54
+ * Add two new assertion methods for Action Cable test cases: `assert_has_no_stream`
55
+ and `assert_has_no_stream_for`.
136
56
 
137
- ```js
138
- import consumer from "./consumer"
57
+ These methods can be used to assert that a stream has been stopped, e.g. via
58
+ `stop_stream` or `stop_stream_for`. They complement the already existing
59
+ `assert_has_stream` and `assert_has_stream_for` methods.
139
60
 
140
- consumer.subscriptions.create("ExampleChannel", {
141
- connected({reconnected}) {
142
- if (reconnected) {
143
- ...
144
- } else {
145
- ...
146
- }
147
- }
148
- })
61
+ ```ruby
62
+ assert_has_no_stream "messages"
63
+ assert_has_no_stream_for User.find(42)
149
64
  ```
150
65
 
151
- *Mansa Keïta*
152
-
153
- * The Redis adapter is now compatible with redis-rb 5.0
154
-
155
- Compatibility with redis-rb 3.x was dropped.
156
-
157
- *Jean Boussier*
158
-
159
- * The Action Cable server is now mounted with `anchor: true`.
160
-
161
- This means that routes that also start with `/cable` will no longer clash with Action Cable.
162
-
163
- *Alex Ghiculescu*
164
-
165
- * `ActionCable.server.remote_connections.where(...).disconnect` now sends `disconnect` message
166
- before closing the connection with the reconnection strategy specified (defaults to `true`).
167
-
168
- *Vladimir Dementyev*
169
-
170
- * Added command callbacks to `ActionCable::Connection::Base`.
171
-
172
- Now you can define `before_command`, `after_command`, and `around_command` to be invoked before, after or around any command received by a client respectively.
173
-
174
- *Vladimir Dementyev*
66
+ *Sebastian Pöll*, *Junichi Sato*
175
67
 
176
- Please check [7-0-stable](https://github.com/rails/rails/blob/7-0-stable/actioncable/CHANGELOG.md) for previous changes.
68
+ Please check [7-1-stable](https://github.com/rails/rails/blob/7-1-stable/actioncable/CHANGELOG.md) for previous changes.
@@ -43,12 +43,11 @@
43
43
  isRunning() {
44
44
  return this.startedAt && !this.stoppedAt;
45
45
  }
46
- recordPing() {
46
+ recordMessage() {
47
47
  this.pingedAt = now();
48
48
  }
49
49
  recordConnect() {
50
50
  this.reconnectAttempts = 0;
51
- this.recordPing();
52
51
  delete this.disconnectedAt;
53
52
  logger.log("ConnectionMonitor recorded connect");
54
53
  }
@@ -236,6 +235,7 @@
236
235
  return;
237
236
  }
238
237
  const {identifier: identifier, message: message, reason: reason, reconnect: reconnect, type: type} = JSON.parse(event.data);
238
+ this.monitor.recordMessage();
239
239
  switch (type) {
240
240
  case message_types.welcome:
241
241
  if (this.triedToReconnect()) {
@@ -251,7 +251,7 @@
251
251
  });
252
252
 
253
253
  case message_types.ping:
254
- return this.monitor.recordPing();
254
+ return null;
255
255
 
256
256
  case message_types.confirmation:
257
257
  this.subscriptions.confirmSubscription(identifier);
@@ -42,12 +42,11 @@ class ConnectionMonitor {
42
42
  isRunning() {
43
43
  return this.startedAt && !this.stoppedAt;
44
44
  }
45
- recordPing() {
45
+ recordMessage() {
46
46
  this.pingedAt = now();
47
47
  }
48
48
  recordConnect() {
49
49
  this.reconnectAttempts = 0;
50
- this.recordPing();
51
50
  delete this.disconnectedAt;
52
51
  logger.log("ConnectionMonitor recorded connect");
53
52
  }
@@ -244,6 +243,7 @@ Connection.prototype.events = {
244
243
  return;
245
244
  }
246
245
  const {identifier: identifier, message: message, reason: reason, reconnect: reconnect, type: type} = JSON.parse(event.data);
246
+ this.monitor.recordMessage();
247
247
  switch (type) {
248
248
  case message_types.welcome:
249
249
  if (this.triedToReconnect()) {
@@ -259,7 +259,7 @@ Connection.prototype.events = {
259
259
  });
260
260
 
261
261
  case message_types.ping:
262
- return this.monitor.recordPing();
262
+ return null;
263
263
 
264
264
  case message_types.confirmation:
265
265
  this.subscriptions.confirmSubscription(identifier);
@@ -43,12 +43,11 @@
43
43
  isRunning() {
44
44
  return this.startedAt && !this.stoppedAt;
45
45
  }
46
- recordPing() {
46
+ recordMessage() {
47
47
  this.pingedAt = now();
48
48
  }
49
49
  recordConnect() {
50
50
  this.reconnectAttempts = 0;
51
- this.recordPing();
52
51
  delete this.disconnectedAt;
53
52
  logger.log("ConnectionMonitor recorded connect");
54
53
  }
@@ -236,6 +235,7 @@
236
235
  return;
237
236
  }
238
237
  const {identifier: identifier, message: message, reason: reason, reconnect: reconnect, type: type} = JSON.parse(event.data);
238
+ this.monitor.recordMessage();
239
239
  switch (type) {
240
240
  case message_types.welcome:
241
241
  if (this.triedToReconnect()) {
@@ -251,7 +251,7 @@
251
251
  });
252
252
 
253
253
  case message_types.ping:
254
- return this.monitor.recordPing();
254
+ return null;
255
255
 
256
256
  case message_types.confirmation:
257
257
  this.subscriptions.confirmSubscription(identifier);
@@ -1,102 +1,112 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "set"
4
6
  require "active_support/rescuable"
5
7
  require "active_support/parameter_filter"
6
8
 
7
9
  module ActionCable
8
10
  module Channel
9
- # = Action Cable \Channel \Base
11
+ # # Action Cable Channel Base
10
12
  #
11
- # The channel provides the basic structure of grouping behavior into logical units when communicating over the WebSocket connection.
12
- # You can think of a channel like a form of controller, but one that's capable of pushing content to the subscriber in addition to simply
13
- # responding to the subscriber's direct requests.
13
+ # The channel provides the basic structure of grouping behavior into logical
14
+ # units when communicating over the WebSocket connection. You can think of a
15
+ # channel like a form of controller, but one that's capable of pushing content
16
+ # to the subscriber in addition to simply responding to the subscriber's direct
17
+ # requests.
14
18
  #
15
- # Channel instances are long-lived. A channel object will be instantiated when the cable consumer becomes a subscriber, and then
16
- # lives until the consumer disconnects. This may be seconds, minutes, hours, or even days. That means you have to take special care
17
- # not to do anything silly in a channel that would balloon its memory footprint or whatever. The references are forever, so they won't be released
18
- # as is normally the case with a controller instance that gets thrown away after every request.
19
+ # Channel instances are long-lived. A channel object will be instantiated when
20
+ # the cable consumer becomes a subscriber, and then lives until the consumer
21
+ # disconnects. This may be seconds, minutes, hours, or even days. That means you
22
+ # have to take special care not to do anything silly in a channel that would
23
+ # balloon its memory footprint or whatever. The references are forever, so they
24
+ # won't be released as is normally the case with a controller instance that gets
25
+ # thrown away after every request.
19
26
  #
20
- # Long-lived channels (and connections) also mean you're responsible for ensuring that the data is fresh. If you hold a reference to a user
21
- # record, but the name is changed while that reference is held, you may be sending stale data if you don't take precautions to avoid it.
27
+ # Long-lived channels (and connections) also mean you're responsible for
28
+ # ensuring that the data is fresh. If you hold a reference to a user record, but
29
+ # the name is changed while that reference is held, you may be sending stale
30
+ # data if you don't take precautions to avoid it.
22
31
  #
23
- # The upside of long-lived channel instances is that you can use instance variables to keep reference to objects that future subscriber requests
24
- # can interact with. Here's a quick example:
32
+ # The upside of long-lived channel instances is that you can use instance
33
+ # variables to keep reference to objects that future subscriber requests can
34
+ # interact with. Here's a quick example:
25
35
  #
26
- # class ChatChannel < ApplicationCable::Channel
27
- # def subscribed
28
- # @room = Chat::Room[params[:room_number]]
29
- # end
36
+ # class ChatChannel < ApplicationCable::Channel
37
+ # def subscribed
38
+ # @room = Chat::Room[params[:room_number]]
39
+ # end
30
40
  #
31
- # def speak(data)
32
- # @room.speak data, user: current_user
41
+ # def speak(data)
42
+ # @room.speak data, user: current_user
43
+ # end
33
44
  # end
34
- # end
35
45
  #
36
- # The #speak action simply uses the Chat::Room object that was created when the channel was first subscribed to by the consumer when that
37
- # subscriber wants to say something in the room.
46
+ # The #speak action simply uses the Chat::Room object that was created when the
47
+ # channel was first subscribed to by the consumer when that subscriber wants to
48
+ # say something in the room.
38
49
  #
39
- # == Action processing
50
+ # ## Action processing
40
51
  #
41
52
  # Unlike subclasses of ActionController::Base, channels do not follow a RESTful
42
53
  # constraint form for their actions. Instead, Action Cable operates through a
43
- # remote-procedure call model. You can declare any public method on the
44
- # channel (optionally taking a <tt>data</tt> argument), and this method is
45
- # automatically exposed as callable to the client.
54
+ # remote-procedure call model. You can declare any public method on the channel
55
+ # (optionally taking a `data` argument), and this method is automatically
56
+ # exposed as callable to the client.
46
57
  #
47
58
  # Example:
48
59
  #
49
- # class AppearanceChannel < ApplicationCable::Channel
50
- # def subscribed
51
- # @connection_token = generate_connection_token
52
- # end
53
- #
54
- # def unsubscribed
55
- # current_user.disappear @connection_token
56
- # end
60
+ # class AppearanceChannel < ApplicationCable::Channel
61
+ # def subscribed
62
+ # @connection_token = generate_connection_token
63
+ # end
57
64
  #
58
- # def appear(data)
59
- # current_user.appear @connection_token, on: data['appearing_on']
60
- # end
65
+ # def unsubscribed
66
+ # current_user.disappear @connection_token
67
+ # end
61
68
  #
62
- # def away
63
- # current_user.away @connection_token
64
- # end
69
+ # def appear(data)
70
+ # current_user.appear @connection_token, on: data['appearing_on']
71
+ # end
65
72
  #
66
- # private
67
- # def generate_connection_token
68
- # SecureRandom.hex(36)
73
+ # def away
74
+ # current_user.away @connection_token
69
75
  # end
70
- # end
71
76
  #
72
- # In this example, the subscribed and unsubscribed methods are not callable methods, as they
73
- # were already declared in ActionCable::Channel::Base, but <tt>#appear</tt>
74
- # and <tt>#away</tt> are. <tt>#generate_connection_token</tt> is also not
75
- # callable, since it's a private method. You'll see that appear accepts a data
76
- # parameter, which it then uses as part of its model call. <tt>#away</tt>
77
- # does not, since it's simply a trigger action.
77
+ # private
78
+ # def generate_connection_token
79
+ # SecureRandom.hex(36)
80
+ # end
81
+ # end
82
+ #
83
+ # In this example, the subscribed and unsubscribed methods are not callable
84
+ # methods, as they were already declared in ActionCable::Channel::Base, but
85
+ # `#appear` and `#away` are. `#generate_connection_token` is also not callable,
86
+ # since it's a private method. You'll see that appear accepts a data parameter,
87
+ # which it then uses as part of its model call. `#away` does not, since it's
88
+ # simply a trigger action.
78
89
  #
79
- # Also note that in this example, <tt>current_user</tt> is available because
80
- # it was marked as an identifying attribute on the connection. All such
81
- # identifiers will automatically create a delegation method of the same name
82
- # on the channel instance.
90
+ # Also note that in this example, `current_user` is available because it was
91
+ # marked as an identifying attribute on the connection. All such identifiers
92
+ # will automatically create a delegation method of the same name on the channel
93
+ # instance.
83
94
  #
84
- # == Rejecting subscription requests
95
+ # ## Rejecting subscription requests
85
96
  #
86
97
  # A channel can reject a subscription request in the #subscribed callback by
87
98
  # invoking the #reject method:
88
99
  #
89
- # class ChatChannel < ApplicationCable::Channel
90
- # def subscribed
91
- # @room = Chat::Room[params[:room_number]]
92
- # reject unless current_user.can_access?(@room)
100
+ # class ChatChannel < ApplicationCable::Channel
101
+ # def subscribed
102
+ # @room = Chat::Room[params[:room_number]]
103
+ # reject unless current_user.can_access?(@room)
104
+ # end
93
105
  # end
94
- # end
95
106
  #
96
- # In this example, the subscription will be rejected if the
97
- # <tt>current_user</tt> does not have access to the chat room. On the
98
- # client-side, the <tt>Channel#rejected</tt> callback will get invoked when
99
- # the server rejects the subscription request.
107
+ # In this example, the subscription will be rejected if the `current_user` does
108
+ # not have access to the chat room. On the client-side, the `Channel#rejected`
109
+ # callback will get invoked when the server rejects the subscription request.
100
110
  class Base
101
111
  include Callbacks
102
112
  include PeriodicTimers
@@ -109,14 +119,13 @@ module ActionCable
109
119
  delegate :logger, to: :connection
110
120
 
111
121
  class << self
112
- # A list of method names that should be considered actions. This
113
- # includes all public instance methods on a channel, less
114
- # any internal methods (defined on Base), adding back in
115
- # any methods that are internal, but still exist on the class
116
- # itself.
122
+ # A list of method names that should be considered actions. This includes all
123
+ # public instance methods on a channel, less any internal methods (defined on
124
+ # Base), adding back in any methods that are internal, but still exist on the
125
+ # class itself.
117
126
  #
118
- # ==== Returns
119
- # * <tt>Set</tt> - A set of all methods that should be considered actions.
127
+ # #### Returns
128
+ # * `Set` - A set of all methods that should be considered actions.
120
129
  def action_methods
121
130
  @action_methods ||= begin
122
131
  # All public instance methods of this class, including ancestors
@@ -130,9 +139,9 @@ module ActionCable
130
139
  end
131
140
 
132
141
  private
133
- # action_methods are cached and there is sometimes need to refresh
134
- # them. ::clear_action_methods! allows you to do that, so next time
135
- # you run action_methods, they will be recalculated.
142
+ # action_methods are cached and there is sometimes need to refresh them.
143
+ # ::clear_action_methods! allows you to do that, so next time you run
144
+ # action_methods, they will be recalculated.
136
145
  def clear_action_methods! # :doc:
137
146
  @action_methods = nil
138
147
  end
@@ -161,9 +170,9 @@ module ActionCable
161
170
  delegate_connection_identifiers
162
171
  end
163
172
 
164
- # Extract the action name from the passed data and process it via the channel. The process will ensure
165
- # that the action requested is a public method on the channel declared by the user (so not one of the callbacks
166
- # like #subscribed).
173
+ # Extract the action name from the passed data and process it via the channel.
174
+ # The process will ensure that the action requested is a public method on the
175
+ # channel declared by the user (so not one of the callbacks like #subscribed).
167
176
  def perform_action(data)
168
177
  action = extract_action(data)
169
178
 
@@ -177,8 +186,8 @@ module ActionCable
177
186
  end
178
187
  end
179
188
 
180
- # This method is called after subscription has been added to the connection
181
- # and confirms or rejects the subscription.
189
+ # This method is called after subscription has been added to the connection and
190
+ # confirms or rejects the subscription.
182
191
  def subscribe_to_channel
183
192
  run_callbacks :subscribe do
184
193
  subscribed
@@ -188,8 +197,9 @@ module ActionCable
188
197
  ensure_confirmation_sent
189
198
  end
190
199
 
191
- # Called by the cable connection when it's cut, so the channel has a chance to cleanup with callbacks.
192
- # This method is not intended to be called directly by the user. Instead, override the #unsubscribed callback.
200
+ # Called by the cable connection when it's cut, so the channel has a chance to
201
+ # cleanup with callbacks. This method is not intended to be called directly by
202
+ # the user. Instead, override the #unsubscribed callback.
193
203
  def unsubscribe_from_channel # :nodoc:
194
204
  run_callbacks :unsubscribe do
195
205
  unsubscribed
@@ -197,20 +207,22 @@ module ActionCable
197
207
  end
198
208
 
199
209
  private
200
- # Called once a consumer has become a subscriber of the channel. Usually the place to set up any streams
201
- # you want this channel to be sending to the subscriber.
210
+ # Called once a consumer has become a subscriber of the channel. Usually the
211
+ # place to set up any streams you want this channel to be sending to the
212
+ # subscriber.
202
213
  def subscribed # :doc:
203
214
  # Override in subclasses
204
215
  end
205
216
 
206
- # Called once a consumer has cut its cable connection. Can be used for cleaning up connections or marking
207
- # users as offline or the like.
217
+ # Called once a consumer has cut its cable connection. Can be used for cleaning
218
+ # up connections or marking users as offline or the like.
208
219
  def unsubscribed # :doc:
209
220
  # Override in subclasses
210
221
  end
211
222
 
212
- # Transmit a hash of data to the subscriber. The hash will automatically be wrapped in a JSON envelope with
213
- # the proper channel identifier marked as the recipient.
223
+ # Transmit a hash of data to the subscriber. The hash will automatically be
224
+ # wrapped in a JSON envelope with the proper channel identifier marked as the
225
+ # recipient.
214
226
  def transmit(data, via: nil) # :doc:
215
227
  logger.debug do
216
228
  status = "#{self.class.name} transmitting #{data.inspect.truncate(300)}"
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "active_support/core_ext/object/to_param"
4
6
 
5
7
  module ActionCable
@@ -7,36 +9,41 @@ module ActionCable
7
9
  module Broadcasting
8
10
  extend ActiveSupport::Concern
9
11
 
10
- included do
11
- delegate :broadcasting_for, :broadcast_to, to: :class
12
- end
13
-
14
12
  module ClassMethods
15
- # Broadcast a hash to a unique broadcasting for this <tt>model</tt> in this channel.
13
+ # Broadcast a hash to a unique broadcasting for this `model` in this channel.
16
14
  def broadcast_to(model, message)
17
15
  ActionCable.server.broadcast(broadcasting_for(model), message)
18
16
  end
19
17
 
20
- # Returns a unique broadcasting identifier for this <tt>model</tt> in this channel:
18
+ # Returns a unique broadcasting identifier for this `model` in this channel:
21
19
  #
22
- # CommentsChannel.broadcasting_for("all") # => "comments:all"
20
+ # CommentsChannel.broadcasting_for("all") # => "comments:all"
23
21
  #
24
- # You can pass any object as a target (e.g. Active Record model), and it
25
- # would be serialized into a string under the hood.
22
+ # You can pass any object as a target (e.g. Active Record model), and it would
23
+ # be serialized into a string under the hood.
26
24
  def broadcasting_for(model)
27
25
  serialize_broadcasting([ channel_name, model ])
28
26
  end
29
27
 
30
- def serialize_broadcasting(object) # :nodoc:
31
- case
32
- when object.is_a?(Array)
33
- object.map { |m| serialize_broadcasting(m) }.join(":")
34
- when object.respond_to?(:to_gid_param)
35
- object.to_gid_param
36
- else
37
- object.to_param
28
+ private
29
+ def serialize_broadcasting(object) # :nodoc:
30
+ case
31
+ when object.is_a?(Array)
32
+ object.map { |m| serialize_broadcasting(m) }.join(":")
33
+ when object.respond_to?(:to_gid_param)
34
+ object.to_gid_param
35
+ else
36
+ object.to_param
37
+ end
38
38
  end
39
- end
39
+ end
40
+
41
+ def broadcasting_for(model)
42
+ self.class.broadcasting_for(model)
43
+ end
44
+
45
+ def broadcast_to(model, message)
46
+ self.class.broadcast_to(model, message)
40
47
  end
41
48
  end
42
49
  end