rage-rb 1.20.1 → 1.21.0
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/CHANGELOG.md +18 -0
- data/README.md +141 -123
- data/lib/rage/all.rb +0 -4
- data/lib/rage/cable/cable.rb +5 -1
- data/lib/rage/cable/channel.rb +53 -1
- data/lib/rage/cli/skills.rb +247 -0
- data/lib/rage/cli.rb +13 -1
- data/lib/rage/controller/api.rb +3 -3
- data/lib/rage/cookies.rb +17 -9
- data/lib/rage/deferred/context.rb +3 -4
- data/lib/rage/deferred/task.rb +2 -2
- data/lib/rage/fiber_scheduler.rb +0 -3
- data/lib/rage/log_processor.rb +6 -10
- data/lib/rage/logger/json_formatter.rb +2 -3
- data/lib/rage/logger/logger.rb +51 -22
- data/lib/rage/logger/text_formatter.rb +2 -3
- data/lib/rage/openapi/collector.rb +1 -0
- data/lib/rage/openapi/openapi.rb +5 -1
- data/lib/rage/router/backend.rb +43 -13
- data/lib/rage/rspec.rb +326 -14
- data/lib/rage/telemetry/tracer.rb +1 -0
- data/lib/rage/templates/config-routes.rb +1 -1
- data/lib/rage/version.rb +1 -1
- metadata +5 -6
- data/lib/rage/sidekiq_session.rb +0 -72
- data/rage.gemspec +0 -38
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7120d5b1b4f9ae8307d199389fe7efbffff3a950d3d312b80c954a00b0c0572e
|
|
4
|
+
data.tar.gz: d3ce27d3cfa545ac38e7b3a7091c24bdd394ab954860da1418a97a16c65ef482
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: aeb7938480349b63ddf30525b7bf89b6c214cf12e1b859311f6c8c7976f4c20866897fbb8cbaefa271fcf65234905b97d0428a1b6f85fb307b91f415abc7538c
|
|
7
|
+
data.tar.gz: 78b9c08dc3769fcec16ec011699d06246e7177d0459e0e4a39a592e5f62386b5142da133337a53eccb2f1c9175a3986a064e0bc16395708901de2c61080acede
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [1.21.0] - 2026-02-25
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- [Cable] Add RSpec test helpers (#210).
|
|
8
|
+
- [Cable] Add support for `stream_for`/`broadcast_to` (#207).
|
|
9
|
+
- Add `skills` CLI (#218).
|
|
10
|
+
- Support inline context for `Rage::Logger` (#206).
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Ensure correct log context isolation for intersecting fibers (#205).
|
|
15
|
+
- Ensure Cable middleware don't duplicate when mounted in routes (#202).
|
|
16
|
+
- Documentation updates by [@cuneyter](https://github.com/cuneyter) (#200).
|
|
17
|
+
- Rely on `Rack::Session` for mounted apps (#201).
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
3
21
|
## [1.20.1] - 2026-02-10
|
|
4
22
|
|
|
5
23
|
### Fixed
|
data/README.md
CHANGED
|
@@ -6,190 +6,208 @@
|
|
|
6
6
|

|
|
7
7
|

|
|
8
8
|
|
|
9
|
-
Rage is
|
|
9
|
+
**Rage** is an API-first Ruby framework with a modern, fiber-based runtime that enables transparent, non-blocking concurrency while preserving familiar developer ergonomics. It focuses on **capability and operational simplicity**, letting teams build production-grade systems in a single, coherent runtime.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Rage uses Rails compatibility as a foundation and provides backend primitives optimized for a single-runtime model: background jobs that run in-process, WebSockets without external dependencies, object-oriented domain events, and automatic API documentation.
|
|
12
12
|
|
|
13
|
-
## Why Rage
|
|
13
|
+
## Why Rage
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Modern backends are more than request/response cycles. They require:
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
* Asynchronous execution
|
|
18
|
+
* Background jobs
|
|
19
|
+
* Real-time communication
|
|
20
|
+
* Observability and telemetry
|
|
21
|
+
* Clear domain boundaries
|
|
18
22
|
|
|
19
|
-
|
|
23
|
+
In the Ruby ecosystem, these concerns typically mean more infrastructure: Redis, Sidekiq, separate worker processes, custom logging solutions, and multiple deployment units.
|
|
20
24
|
|
|
21
|
-
|
|
22
|
-
- **True concurrency** - Fiber-based architecture handles I/O without threads, locks, or async/await syntax. Your code looks synchronous but runs concurrently.
|
|
23
|
-
- **Zero-dependency WebSockets** - Action Cable-compatible real-time features that work out-of-the-box without Redis, even in multi-process mode.
|
|
24
|
-
- **Auto-generated OpenAPI** - Documentation generated from your controllers using simple comment tags.
|
|
25
|
-
- **In-process Background jobs** - A durable, persistent queue that runs inside your app process. No Redis or separate worker processes required.
|
|
26
|
-
- **Built-in Observability** - Track and measure application behavior with `Rage::Telemetry`. Integrate with external monitoring platforms or build custom observability solutions.
|
|
27
|
-
- **Stable and focused** - Our goal is that the task "Upgrade Rage" never appears in your ticketing system. We focus strictly on APIs, maintain long-term deprecation cycles, and ensure that most updates are as simple as a `bundle update`.
|
|
25
|
+
Rage takes a different approach: **collapse backend concerns into a single runtime** by embracing Ruby's fiber-based concurrency model. This reduces operational complexity while keeping familiar Ruby ergonomics.
|
|
28
26
|
|
|
29
|
-
|
|
27
|
+
### Unified Runtime in Action
|
|
30
28
|
|
|
31
|
-
|
|
29
|
+
Here's what single runtime looks like in practice:
|
|
32
30
|
|
|
33
|
-
|
|
31
|
+
```ruby
|
|
32
|
+
class OrdersController < RageController::API
|
|
33
|
+
def create
|
|
34
|
+
order = Order.create!(order_params)
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
```
|
|
36
|
+
# Schedule background job - runs in-process, no Redis needed
|
|
37
|
+
SendOrderConfirmation.enqueue(order.id)
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
# Publish domain event - subscribers execute immediately or async
|
|
40
|
+
Rage::Events.publish(OrderPlaced.new(order: order))
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
```
|
|
42
|
+
# Broadcast to WebSocket subscribers - no Action Cable/Redis needed
|
|
43
|
+
Rage::Cable.broadcast("orders", { status: "created", order_id: order.id })
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
render json: order, status: :created
|
|
46
|
+
end
|
|
47
|
+
end
|
|
46
48
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
# Background job - runs in the same process, persisted to disk
|
|
50
|
+
class SendOrderConfirmation
|
|
51
|
+
include Rage::Deferred::Task
|
|
52
|
+
|
|
53
|
+
def perform(order_id)
|
|
54
|
+
order = Order.find(order_id)
|
|
55
|
+
OrderMailer.confirmation(order).deliver
|
|
56
|
+
end
|
|
57
|
+
end
|
|
51
58
|
|
|
52
|
-
|
|
59
|
+
# Domain event - typed, object-oriented
|
|
60
|
+
OrderPlaced = Data.define(:order)
|
|
53
61
|
|
|
54
|
-
|
|
55
|
-
|
|
62
|
+
# Event subscriber
|
|
63
|
+
class UpdateInventory
|
|
64
|
+
include Rage::Events::Subscriber
|
|
65
|
+
subscribe_to OrderPlaced
|
|
66
|
+
|
|
67
|
+
def call(event)
|
|
68
|
+
Inventory.decrement(event.order.items.length)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
56
71
|
```
|
|
57
72
|
|
|
58
|
-
|
|
73
|
+
This all runs in a single process. No external queues, no separate worker dynos, no Redis for pub/sub.
|
|
59
74
|
|
|
60
|
-
##
|
|
75
|
+
## Coming from Rails?
|
|
61
76
|
|
|
62
|
-
Rage
|
|
77
|
+
Rage keeps the parts of Rails that work - controllers, routing, Active Record compatibility, and conventions - but rethinks how backend systems are run.
|
|
63
78
|
|
|
64
|
-
|
|
79
|
+
Instead of adding separate job queues, Redis, and multiple deployment units as your app grows, Rage uses Ruby's fiber-based concurrency to run APIs, background jobs, WebSockets, and domain events **in the same process**.
|
|
65
80
|
|
|
66
|
-
|
|
81
|
+
You write familiar synchronous Ruby code. Rage handles the concurrency.
|
|
67
82
|
|
|
68
|
-
|
|
83
|
+
**What changes:**
|
|
69
84
|
|
|
70
|
-
|
|
71
|
-
|
|
85
|
+
- One deployment unit instead of API servers + worker processes
|
|
86
|
+
- No Redis required for jobs or broadcasts
|
|
87
|
+
- Domain events as objects, not string-based notifications
|
|
88
|
+
- OpenAPI specs generated automatically from your code
|
|
72
89
|
|
|
73
|
-
|
|
74
|
-
rescue_from SocketError do |_|
|
|
75
|
-
render json: { message: "error" }, status: 500
|
|
76
|
-
end
|
|
90
|
+
**What stays the same:**
|
|
77
91
|
|
|
78
|
-
|
|
92
|
+
- Controller conventions and routing DSL
|
|
93
|
+
- Active Record integration
|
|
94
|
+
- Incremental adoption for existing Rails apps
|
|
79
95
|
|
|
80
|
-
|
|
81
|
-
page = Net::HTTP.get(URI("https://httpbin.org/json"))
|
|
82
|
-
render json: { page: page, metadata: @metadata }
|
|
83
|
-
end
|
|
96
|
+
Think of Rage as Rails ergonomics with a runtime designed for modern API systems, where operational simplicity is a first-class concern.
|
|
84
97
|
|
|
85
|
-
|
|
98
|
+
## Core Ideas
|
|
86
99
|
|
|
87
|
-
|
|
88
|
-
@metadata = { format: "json", time: Time.now.to_i }
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
```
|
|
100
|
+
### 1. Unified Backend Runtime
|
|
92
101
|
|
|
93
|
-
|
|
102
|
+
Rage runs HTTP APIs, background jobs, and WebSockets in the same process by default:
|
|
94
103
|
|
|
95
|
-
|
|
104
|
+
- No separate worker processes
|
|
105
|
+
- No Redis required for jobs or broadcasts
|
|
106
|
+
- One deployment unit for most applications
|
|
96
107
|
|
|
97
|
-
|
|
98
|
-
Rage.routes.draw do
|
|
99
|
-
get "page", to: "pages#show"
|
|
100
|
-
end
|
|
101
|
-
```
|
|
108
|
+
This simplifies both local development and production setup.
|
|
102
109
|
|
|
103
|
-
|
|
110
|
+
For high-scale scenarios, Rage supports multi-process deployments and allows Rage processes to communicate directly when needed.
|
|
104
111
|
|
|
105
|
-
|
|
112
|
+
### 2. API-First, Rails-Compatible
|
|
106
113
|
|
|
107
|
-
|
|
108
|
-
require "net/http"
|
|
114
|
+
Rage provides a familiar Rails-like programming model with API-focused improvements:
|
|
109
115
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
Fiber.schedule { Net::HTTP.get(URI("https://httpbin.org/html")) },
|
|
115
|
-
])
|
|
116
|
+
- Controllers and routing that feel like Rails
|
|
117
|
+
- Active Record compatibility
|
|
118
|
+
- Incremental adoption for existing Rails applications
|
|
119
|
+
- OpenAPI specs auto-generated from your code
|
|
116
120
|
|
|
117
|
-
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
```
|
|
121
|
+
Rails compatibility is the foundation. Rage builds on top of that foundation with new primitives designed for high-concurrency, API-first architectures.
|
|
121
122
|
|
|
122
|
-
|
|
123
|
+
### 3. Built-in Asynchronous Execution
|
|
123
124
|
|
|
124
|
-
|
|
125
|
+
Rage ships with **fiber-based, in-process background jobs**:
|
|
125
126
|
|
|
126
|
-
|
|
127
|
+
- Zero setup - no Redis, no configuration
|
|
128
|
+
- Jobs persist across restarts
|
|
129
|
+
- Scheduled and executed within the same runtime using fibers for concurrency
|
|
127
130
|
|
|
128
|
-
|
|
131
|
+
For teams that need distributed job processing, Rage works with existing solutions. But most applications can start simple and stay simple.
|
|
129
132
|
|
|
130
|
-
|
|
133
|
+
### 4. Structured Domain Events
|
|
131
134
|
|
|
132
|
-
|
|
133
|
-
- [Controllers](https://rage-rb.dev/docs/controllers/) - Request handling and callbacks
|
|
134
|
-
- [Routing](https://rage-rb.dev/docs/routing/) - RESTful routes and namespaces
|
|
135
|
-
- [WebSockets](https://rage-rb.dev/docs/websockets/) - Real-time communication
|
|
136
|
-
- [OpenAPI](https://rage-rb.dev/docs/openapi/) - Auto-generated documentation
|
|
137
|
-
- [Background Jobs](https://rage-rb.dev/docs/deferred/) - In-process queue system
|
|
138
|
-
- [API Reference](https://rage-rb.dev/api/) - Detailed API documentation
|
|
135
|
+
Rage includes a built‑in event bus designed for **object‑oriented domain events**:
|
|
139
136
|
|
|
140
|
-
|
|
137
|
+
* Events are classes with explicit attributes, not hashes or strings
|
|
138
|
+
* Subscribers listen to event classes or mixins
|
|
139
|
+
* Type-safe and refactorable
|
|
141
140
|
|
|
142
|
-
|
|
141
|
+
This encourages clear domain modeling and avoids the brittleness of string-based notification systems.
|
|
143
142
|
|
|
144
|
-
|
|
143
|
+
### 5. Observability by Design
|
|
145
144
|
|
|
146
|
-
|
|
145
|
+
Observability is not an afterthought:
|
|
147
146
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
render json: { hello: "world" }
|
|
152
|
-
end
|
|
153
|
-
end
|
|
154
|
-
```
|
|
147
|
+
- Structured logging by default
|
|
148
|
+
- Dedicated observability interface for HTTP, background, and real-time features
|
|
149
|
+
- OpenAPI specifications generated automatically from the running application
|
|
155
150
|
|
|
156
|
-
|
|
151
|
+
API contracts stay in sync with code by default - no separate documentation pipelines.
|
|
157
152
|
|
|
153
|
+
### 6. Performance That Enables Simplicity
|
|
158
154
|
|
|
159
|
-
|
|
155
|
+
Rage's fiber-based concurrency delivers strong performance for I/O-heavy workloads, but performance is a means to an end: operational simplicity.
|
|
160
156
|
|
|
161
|
-
|
|
162
|
-
class BenchmarksController < ApplicationController
|
|
163
|
-
def index
|
|
164
|
-
Net::HTTP.get(URI("<endpoint-that-responds-in-one-second>"))
|
|
165
|
-
head :ok
|
|
166
|
-
end
|
|
167
|
-
end
|
|
168
|
-
```
|
|
157
|
+
By handling concurrency efficiently, Rage lets you:
|
|
169
158
|
|
|
170
|
-
|
|
159
|
+
- Run fewer servers
|
|
160
|
+
- Deploy fewer services
|
|
161
|
+
- Reduce infrastructure by handling workloads that traditionally required separate microservices
|
|
171
162
|
|
|
172
|
-
|
|
163
|
+
The goal is to let teams write maintainable Ruby code while natively handling massive concurrency, eliminating the need for premature optimization or infrastructure sprawl.
|
|
173
164
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
165
|
+
## Philosophy
|
|
166
|
+
|
|
167
|
+
Rage is intentionally conservative about change.
|
|
168
|
+
|
|
169
|
+
The framework prioritizes:
|
|
170
|
+
|
|
171
|
+
- **Stable public APIs**
|
|
172
|
+
- **Long deprecation cycles**
|
|
173
|
+
- **Minimal external dependencies**
|
|
174
|
+
|
|
175
|
+
The goal is to let teams build systems that **age well** - without constant rewrites or growing infrastructure complexity.
|
|
176
|
+
|
|
177
|
+
Our aspiration: the task "Upgrade Rage" never appears in your ticketing system. Most updates should be as simple as `bundle update`.
|
|
178
|
+
|
|
179
|
+
## What Rage Is (and Isn't)
|
|
180
|
+
|
|
181
|
+
**Rage is:**
|
|
182
|
+
|
|
183
|
+
- Focused on backend APIs
|
|
184
|
+
- Opinionated about operational simplicity
|
|
185
|
+
- Designed for long-term stability
|
|
186
|
+
- Rails-compatible but architecturally independent
|
|
187
|
+
|
|
188
|
+
**Rage is not:**
|
|
189
|
+
|
|
190
|
+
- A full-stack framework - no view layer, no asset pipeline
|
|
191
|
+
- A Rails clone - compatibility is a bridge, not the destination
|
|
192
|
+
- Trying to do everything - deliberate scope boundaries
|
|
181
193
|
|
|
182
|
-
|
|
194
|
+
## Who Rage Is For
|
|
183
195
|
|
|
184
|
-
|
|
196
|
+
Rage is a good fit if you:
|
|
185
197
|
|
|
186
|
-
|
|
198
|
+
- Build API-only backends in Ruby
|
|
199
|
+
- Care about operational simplicity over maximum flexibility
|
|
200
|
+
- Want fewer moving parts in production
|
|
201
|
+
- Prefer explicit, object-oriented design
|
|
202
|
+
- Value long-term stability over cutting-edge features
|
|
187
203
|
|
|
188
|
-
|
|
204
|
+
## Learn More
|
|
189
205
|
|
|
190
|
-
|
|
206
|
+
- Documentation: [https://rage-rb.dev](https://rage-rb.dev/docs/intro)
|
|
207
|
+
- API Reference: [https://rage-rb.dev/api](https://rage-rb.dev/api)
|
|
208
|
+
- Architecture: [ARCHITECTURE.md](https://github.com/rage-rb/rage/blob/main/ARCHITECTURE.md)
|
|
191
209
|
|
|
192
|
-
|
|
210
|
+
Contributions and thoughtful feedback are welcome.
|
|
193
211
|
|
|
194
212
|
## License
|
|
195
213
|
|
data/lib/rage/all.rb
CHANGED
data/lib/rage/cable/cable.rb
CHANGED
|
@@ -53,7 +53,11 @@ module Rage::Cable
|
|
|
53
53
|
end
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
-
Rage.with_middlewares(application, Rage.config.cable.middlewares)
|
|
56
|
+
chain = Rage.with_middlewares(application, Rage.config.cable.middlewares)
|
|
57
|
+
application.define_singleton_method(:__rage_app_name) { "Rage::Cable" }
|
|
58
|
+
chain.define_singleton_method(:__rage_root_app) { application }
|
|
59
|
+
|
|
60
|
+
chain
|
|
57
61
|
end
|
|
58
62
|
|
|
59
63
|
# @private
|
data/lib/rage/cable/channel.rb
CHANGED
|
@@ -289,6 +289,32 @@ class Rage::Cable::Channel
|
|
|
289
289
|
@__periodic_timers << [callback, every]
|
|
290
290
|
end
|
|
291
291
|
|
|
292
|
+
# Broadcast data to all the clients subscribed to a channel-local stream.
|
|
293
|
+
#
|
|
294
|
+
# @param streamable [#id, String, Symbol, Numeric, Array] an object that will be used to generate the stream name
|
|
295
|
+
# @param data [Object] the data to send to the clients
|
|
296
|
+
# @raise [ArgumentError] if the streamable object does not satisfy the type requirements
|
|
297
|
+
# @example
|
|
298
|
+
# NotificationsChannel.broadcast_to(current_user, { message: "You have a new notification!" })
|
|
299
|
+
def broadcast_to(streamable, data)
|
|
300
|
+
Rage.cable.broadcast(__stream_name_for(streamable), data)
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
# @private
|
|
304
|
+
def __stream_name_for(streamables)
|
|
305
|
+
stream_name = Array(streamables).map do |streamable|
|
|
306
|
+
if streamable.respond_to?(:id)
|
|
307
|
+
"#{streamable.class.name}:#{streamable.id}"
|
|
308
|
+
elsif streamable.is_a?(String) || streamable.is_a?(Symbol) || streamable.is_a?(Numeric)
|
|
309
|
+
streamable
|
|
310
|
+
else
|
|
311
|
+
raise ArgumentError, "Unable to generate stream name. Expected an object that responds to `id`, got: #{streamable.class}"
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
"#{name}:#{stream_name.join(":")}"
|
|
316
|
+
end
|
|
317
|
+
|
|
292
318
|
protected
|
|
293
319
|
|
|
294
320
|
def set_up_periodic_timers
|
|
@@ -407,13 +433,39 @@ class Rage::Cable::Channel
|
|
|
407
433
|
!!@__subscription_rejected
|
|
408
434
|
end
|
|
409
435
|
|
|
410
|
-
# Subscribe to a stream.
|
|
436
|
+
# Subscribe to a stream global stream. Global streams are not associated with any specific channel instance and can be used to broadcast data to multiple channels at once.
|
|
411
437
|
#
|
|
412
438
|
# @param stream [String] the name of the stream
|
|
439
|
+
# @raise [ArgumentError] if the stream name is not a String
|
|
440
|
+
# @example Subscribe to a stream
|
|
441
|
+
# class NotificationsChannel < Rage::Cable::Channel
|
|
442
|
+
# def subscribed
|
|
443
|
+
# stream_from "notifications"
|
|
444
|
+
# end
|
|
445
|
+
# end
|
|
446
|
+
# @example Broadcast to the stream
|
|
447
|
+
# Rage::Cable.broadcast("notifications", { message: "A new member has joined!" })
|
|
413
448
|
def stream_from(stream)
|
|
449
|
+
raise ArgumentError, "Stream name must be a String" unless stream.is_a?(String)
|
|
414
450
|
Rage.cable.__protocol.subscribe(@__connection, stream, @__params)
|
|
415
451
|
end
|
|
416
452
|
|
|
453
|
+
# Subscribe to a local stream. Local streams are associated with a specific channel instance and can be used to send data to the current channel only.
|
|
454
|
+
#
|
|
455
|
+
# @param streamable [#id, String, Symbol, Numeric, Array] an object that will be used to generate the stream name
|
|
456
|
+
# @raise [ArgumentError] if the streamable object does not satisfy the type requirements
|
|
457
|
+
# @example Subscribe to a stream
|
|
458
|
+
# class NotificationsChannel < Rage::Cable::Channel
|
|
459
|
+
# def subscribed
|
|
460
|
+
# stream_for current_user
|
|
461
|
+
# end
|
|
462
|
+
# end
|
|
463
|
+
# @example Broadcast to the stream
|
|
464
|
+
# NotificationsChannel.broadcast_to(current_user, { message: "You have a new notification!" })
|
|
465
|
+
def stream_for(streamable)
|
|
466
|
+
stream_from(self.class.__stream_name_for(streamable))
|
|
467
|
+
end
|
|
468
|
+
|
|
417
469
|
# Broadcast data to all the clients subscribed to a stream.
|
|
418
470
|
#
|
|
419
471
|
# @param stream [String] the name of the stream
|