mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
backports cable guide and index updates
This commit is contained in:
parent
60cffd8712
commit
1672ec88c6
2 changed files with 197 additions and 150 deletions
|
@ -12,41 +12,39 @@ After reading this guide, you will know:
|
|||
Introduction
|
||||
------------
|
||||
|
||||
Action Cable seamlessly integrates WebSockets with the rest of your Rails application.
|
||||
It allows for real-time features to be written in Ruby in the same style and form as
|
||||
the rest of your Rails application, while still being performant and scalable. It's
|
||||
a full-stack offering that provides both a client-side JavaScript framework and a
|
||||
server-side Ruby framework. You have access to your full domain model written with
|
||||
Active Record or your ORM of choice.
|
||||
Action Cable seamlessly integrates
|
||||
[WebSockets](https://en.wikipedia.org/wiki/WebSocket) with the rest of your
|
||||
Rails application. It allows for real-time features to be written in Ruby in the
|
||||
same style and form as the rest of your Rails application, while still being
|
||||
performant and scalable. It's a full-stack offering that provides both a
|
||||
client-side JavaScript framework and a server-side Ruby framework. You have
|
||||
access to your full domain model written with Active Record or your ORM of
|
||||
choice.
|
||||
|
||||
What is Pub/Sub
|
||||
---------------
|
||||
|
||||
Pub/Sub, or Publish-Subscribe, refers to a message queue paradigm whereby senders
|
||||
of information (publishers), send data to an abstract class of recipients (subscribers),
|
||||
without specifying individual recipients. Action Cable uses this approach to communicate
|
||||
between the server and many clients.
|
||||
|
||||
What is Action Cable
|
||||
--------------------
|
||||
|
||||
Action Cable is a server which can handle multiple connection instances, with one
|
||||
client-server connection instance established per WebSocket connection.
|
||||
[Pub/Sub](https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern), or
|
||||
Publish-Subscribe, refers to a message queue paradigm whereby senders of
|
||||
information (publishers), send data to an abstract class of recipients
|
||||
(subscribers), without specifying individual recipients. Action Cable uses this
|
||||
approach to communicate between the server and many clients.
|
||||
|
||||
## Server-Side Components
|
||||
|
||||
### Connections
|
||||
|
||||
Connections form the foundation of the client-server relationship. For every WebSocket
|
||||
the cable server is accepting, a Connection object will be instantiated on the server side.
|
||||
This instance becomes the parent of all the channel subscriptions that are created from there on.
|
||||
The Connection itself does not deal with any specific application logic beyond authentication
|
||||
and authorization. The client of a WebSocket connection is called a consumer. An individual
|
||||
user will create one consumer-connection pair per browser tab, window, or device they have open.
|
||||
*Connections* form the foundation of the client-server relationship. For every
|
||||
WebSocket accepted by the server, a connection object is instantiated. This
|
||||
object becomes the parent of all the *channel subscriptions* that are created
|
||||
from there on. The connection itself does not deal with any specific application
|
||||
logic beyond authentication and authorization. The client of a WebSocket
|
||||
connection is called the connection *consumer*. An individual user will create
|
||||
one consumer-connection pair per browser tab, window, or device they have open.
|
||||
|
||||
Connections are instantiated via the `ApplicationCable::Connection` class in Ruby.
|
||||
In this class, you authorize the incoming connection, and proceed to establish it
|
||||
if the user can be identified.
|
||||
Connections are instances of `ApplicationCable::Connection`. In this class, you
|
||||
authorize the incoming connection, and proceed to establish it if the user can
|
||||
be identified.
|
||||
|
||||
#### Connection Setup
|
||||
|
||||
|
@ -78,17 +76,17 @@ create a delegate by the same name on any channel instances created off the conn
|
|||
|
||||
This example relies on the fact that you will already have handled authentication of the user
|
||||
somewhere else in your application, and that a successful authentication sets a signed
|
||||
cookie with the `user_id`.
|
||||
cookie with the user ID.
|
||||
|
||||
The cookie is then automatically sent to the connection instance when a new connection
|
||||
is attempted, and you use that to set the `current_user`. By identifying the connection
|
||||
by this same current_user, you're also ensuring that you can later retrieve all open
|
||||
by this same current user, you're also ensuring that you can later retrieve all open
|
||||
connections by a given user (and potentially disconnect them all if the user is deleted
|
||||
or deauthorized).
|
||||
|
||||
### Channels
|
||||
|
||||
A channel encapsulates a logical unit of work, similar to what a controller does in a
|
||||
A *channel* encapsulates a logical unit of work, similar to what a controller does in a
|
||||
regular MVC setup. By default, Rails creates a parent `ApplicationCable::Channel` class
|
||||
for encapsulating shared logic between your channels.
|
||||
|
||||
|
@ -103,7 +101,7 @@ end
|
|||
```
|
||||
|
||||
Then you would create your own channel classes. For example, you could have a
|
||||
**ChatChannel** and an **AppearanceChannel**:
|
||||
`ChatChannel` and an `AppearanceChannel`:
|
||||
|
||||
```ruby
|
||||
# app/channels/chat_channel.rb
|
||||
|
@ -119,15 +117,15 @@ A consumer could then be subscribed to either or both of these channels.
|
|||
|
||||
#### Subscriptions
|
||||
|
||||
When a consumer is subscribed to a channel, they act as a subscriber;
|
||||
This connection is called a subscription.
|
||||
Incoming messages are then routed to these channel subscriptions based on
|
||||
an identifier sent by the cable consumer.
|
||||
Consumers subscribe to channels, acting as *subscribers*. Their connection is
|
||||
called a *subscription*. Produced messages are then routed to these channel
|
||||
subscriptions based on an identifier sent by the cable consumer.
|
||||
|
||||
```ruby
|
||||
# app/channels/chat_channel.rb
|
||||
class ChatChannel < ApplicationCable::Channel
|
||||
# Called when the consumer has successfully become a subscriber of this channel
|
||||
# Called when the consumer has successfully
|
||||
# become a subscriber of this channel.
|
||||
def subscribed
|
||||
end
|
||||
end
|
||||
|
@ -138,30 +136,30 @@ end
|
|||
### Connections
|
||||
|
||||
Consumers require an instance of the connection on their side. This can be
|
||||
established using the following Javascript, which is generated by default in Rails:
|
||||
established using the following JavaScript, which is generated by default by Rails:
|
||||
|
||||
#### Connect Consumer
|
||||
|
||||
```coffeescript
|
||||
# app/assets/javascripts/cable.coffee
|
||||
#= require action_cable
|
||||
```js
|
||||
// app/assets/javascripts/cable.js
|
||||
//= require action_cable
|
||||
//= require_self
|
||||
//= require_tree ./channels
|
||||
|
||||
@App = {}
|
||||
App.cable = ActionCable.createConsumer()
|
||||
(function() {
|
||||
this.App || (this.App = {});
|
||||
|
||||
App.cable = ActionCable.createConsumer();
|
||||
}).call(this);
|
||||
```
|
||||
|
||||
This will ready a consumer that'll connect against /cable on your server by default.
|
||||
This will ready a consumer that'll connect against `/cable` on your server by default.
|
||||
The connection won't be established until you've also specified at least one subscription
|
||||
you're interested in having.
|
||||
|
||||
#### Subscriber
|
||||
|
||||
When a consumer is subscribed to a channel, they act as a subscriber. A
|
||||
consumer can act as a subscriber to a given channel any number of times.
|
||||
For example, a consumer could subscribe to multiple chat rooms at the same time.
|
||||
(remember that a physical user may have multiple consumers, one per tab/device open to your connection).
|
||||
|
||||
A consumer becomes a subscriber, by creating a subscription to a given channel:
|
||||
A consumer becomes a subscriber by creating a subscription to a given channel:
|
||||
|
||||
```coffeescript
|
||||
# app/assets/javascripts/cable/subscriptions/chat.coffee
|
||||
|
@ -174,12 +172,20 @@ App.cable.subscriptions.create { channel: "AppearanceChannel" }
|
|||
While this creates the subscription, the functionality needed to respond to
|
||||
received data will be described later on.
|
||||
|
||||
A consumer can act as a subscriber to a given channel any number of times. For
|
||||
example, a consumer could subscribe to multiple chat rooms at the same time:
|
||||
|
||||
```coffeescript
|
||||
App.cable.subscriptions.create { channel: "ChatChannel", room: "1st Room" }
|
||||
App.cable.subscriptions.create { channel: "ChatChannel", room: "2nd Room" }
|
||||
```
|
||||
|
||||
## Client-Server Interactions
|
||||
|
||||
### Streams
|
||||
|
||||
Streams provide the mechanism by which channels route published content
|
||||
(broadcasts) to its subscribers.
|
||||
*Streams* provide the mechanism by which channels route published content
|
||||
(broadcasts) to their subscribers.
|
||||
|
||||
```ruby
|
||||
# app/channels/chat_channel.rb
|
||||
|
@ -203,21 +209,30 @@ class CommentsChannel < ApplicationCable::Channel
|
|||
end
|
||||
```
|
||||
|
||||
You can then broadcast to this channel using: `CommentsChannel.broadcast_to(@post, @comment)`
|
||||
You can then broadcast to this channel like this:
|
||||
|
||||
### Broadcastings
|
||||
```ruby
|
||||
CommentsChannel.broadcast_to(@post, @comment)
|
||||
```
|
||||
|
||||
A broadcasting is a pub/sub link where anything transmitted by a publisher
|
||||
### Broadcasting
|
||||
|
||||
A *broadcasting* is a pub/sub link where anything transmitted by a publisher
|
||||
is routed directly to the channel subscribers who are streaming that named
|
||||
broadcasting. Each channel can be streaming zero or more broadcastings.
|
||||
Broadcastings are purely an online queue and time dependent;
|
||||
If a consumer is not streaming (subscribed to a given channel), they'll not
|
||||
get the broadcast should they connect later.
|
||||
|
||||
Broadcastings are purely an online queue and time dependent. If a consumer is
|
||||
not streaming (subscribed to a given channel), they'll not get the broadcast
|
||||
should they connect later.
|
||||
|
||||
Broadcasts are called elsewhere in your Rails application:
|
||||
|
||||
```ruby
|
||||
WebNotificationsChannel.broadcast_to current_user, title: 'New things!', body: 'All the news fit to print'
|
||||
WebNotificationsChannel.broadcast_to(
|
||||
current_user,
|
||||
title: 'New things!',
|
||||
body: 'All the news fit to print'
|
||||
)
|
||||
```
|
||||
|
||||
The `WebNotificationsChannel.broadcast_to` call places a message in the current
|
||||
|
@ -226,14 +241,14 @@ broadcasting name for each user. For a user with an ID of 1, the broadcasting
|
|||
name would be `web_notifications_1`.
|
||||
|
||||
The channel has been instructed to stream everything that arrives at
|
||||
`web_notifications_1` directly to the client by invoking the `#received(data)`
|
||||
`web_notifications_1` directly to the client by invoking the `received`
|
||||
callback.
|
||||
|
||||
### Subscriptions
|
||||
|
||||
When a consumer is subscribed to a channel, they act as a subscriber;
|
||||
This connection is called a subscription. Incoming messages are then routed
|
||||
to these channel subscriptions based on an identifier sent by the cable consumer.
|
||||
When a consumer is subscribed to a channel, they act as a subscriber. This
|
||||
connection is called a subscription. Incoming messages are then routed to
|
||||
these channel subscriptions based on an identifier sent by the cable consumer.
|
||||
|
||||
```coffeescript
|
||||
# app/assets/javascripts/cable/subscriptions/chat.coffee
|
||||
|
@ -255,10 +270,10 @@ App.cable.subscriptions.create { channel: "ChatChannel", room: "Best Room" },
|
|||
"""
|
||||
```
|
||||
|
||||
### Passing Parameters to Channel
|
||||
### Passing Parameters to Channels
|
||||
|
||||
You can pass parameters from the client-side to the server-side when
|
||||
creating a subscription. For example:
|
||||
You can pass parameters from the client side to the server side when creating a
|
||||
subscription. For example:
|
||||
|
||||
```ruby
|
||||
# app/channels/chat_channel.rb
|
||||
|
@ -269,8 +284,8 @@ class ChatChannel < ApplicationCable::Channel
|
|||
end
|
||||
```
|
||||
|
||||
Pass an object as the first argument to `subscriptions.create`, and that object
|
||||
will become your params hash in your cable channel. The keyword `channel` is required.
|
||||
An object passed as the first argument to `subscriptions.create` becomes the
|
||||
params hash in the cable channel. The keyword `channel` is required:
|
||||
|
||||
```coffeescript
|
||||
# app/assets/javascripts/cable/subscriptions/chat.coffee
|
||||
|
@ -292,14 +307,18 @@ App.cable.subscriptions.create { channel: "ChatChannel", room: "Best Room" },
|
|||
```
|
||||
|
||||
```ruby
|
||||
# Somewhere in your app this is called, perhaps from a NewCommentJob
|
||||
ChatChannel.broadcast_to "chat_#{room}", sent_by: 'Paul', body: 'This is a cool chat app.'
|
||||
# Somewhere in your app this is called, perhaps
|
||||
# from a NewCommentJob.
|
||||
ChatChannel.broadcast_to(
|
||||
"chat_#{room}",
|
||||
sent_by: 'Paul',
|
||||
body: 'This is a cool chat app.'
|
||||
)
|
||||
```
|
||||
|
||||
### Rebroadcasting a Message
|
||||
|
||||
### Rebroadcasting message
|
||||
|
||||
A common use case is to rebroadcast a message sent by one client to any
|
||||
A common use case is to *rebroadcast* a message sent by one client to any
|
||||
other connected clients.
|
||||
|
||||
```ruby
|
||||
|
@ -310,7 +329,7 @@ class ChatChannel < ApplicationCable::Channel
|
|||
end
|
||||
|
||||
def receive(data)
|
||||
ChatChannel.broadcast_to "chat_#{params[:room]}", data
|
||||
ChatChannel.broadcast_to("chat_#{params[:room]}", data)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
@ -328,20 +347,21 @@ The rebroadcast will be received by all connected clients, _including_ the
|
|||
client that sent the message. Note that params are the same as they were when
|
||||
you subscribed to the channel.
|
||||
|
||||
## Full-stack examples
|
||||
## Full-Stack Examples
|
||||
|
||||
The following setup steps are common to both examples:
|
||||
|
||||
1. [Setup your connection](#connection-setup)
|
||||
2. [Setup your parent channel](#parent-channel-setup)
|
||||
3. [Connect your consumer](#connect-consumer)
|
||||
1. [Setup your connection](#connection-setup).
|
||||
2. [Setup your parent channel](#parent-channel-setup).
|
||||
3. [Connect your consumer](#connect-consumer).
|
||||
|
||||
### Example 1: User Appearances
|
||||
|
||||
### Example 1: User appearances
|
||||
Here's a simple example of a channel that tracks whether a user is online or not
|
||||
and what page they're on. (This is useful for creating presence features like showing
|
||||
a green dot next to a user name if they're online).
|
||||
|
||||
#### Create the server-side Appearance Channel:
|
||||
Create the server-side appearance channel:
|
||||
|
||||
```ruby
|
||||
# app/channels/appearance_channel.rb
|
||||
|
@ -355,7 +375,7 @@ class AppearanceChannel < ApplicationCable::Channel
|
|||
end
|
||||
|
||||
def appear(data)
|
||||
current_user.appear on: data['appearing_on']
|
||||
current_user.appear(on: data['appearing_on'])
|
||||
end
|
||||
|
||||
def away
|
||||
|
@ -364,35 +384,34 @@ class AppearanceChannel < ApplicationCable::Channel
|
|||
end
|
||||
```
|
||||
|
||||
When `#subscribed` callback is invoked by the consumer, a client-side subscription
|
||||
is initiated. In this case, we take that opportunity to say "the current user has
|
||||
indeed appeared". That appear/disappear API could be backed by Redis, a database,
|
||||
or whatever else.
|
||||
When a subscription is initiated the `subscribed` callback gets fired and we
|
||||
take that opportunity to say "the current user has indeed appeared". That
|
||||
appear/disappear API could be backed by Redis, a database, or whatever else.
|
||||
|
||||
#### Create the client-side Appearance Channel subscription:
|
||||
Create the client-side appearance channel subscription:
|
||||
|
||||
```coffeescript
|
||||
# app/assets/javascripts/cable/subscriptions/appearance.coffee
|
||||
App.cable.subscriptions.create "AppearanceChannel",
|
||||
# Called when the subscription is ready for use on the server
|
||||
# Called when the subscription is ready for use on the server.
|
||||
connected: ->
|
||||
@install()
|
||||
@appear()
|
||||
|
||||
# Called when the WebSocket connection is closed
|
||||
# Called when the WebSocket connection is closed.
|
||||
disconnected: ->
|
||||
@uninstall()
|
||||
|
||||
# Called when the subscription is rejected by the server
|
||||
# Called when the subscription is rejected by the server.
|
||||
rejected: ->
|
||||
@uninstall()
|
||||
|
||||
appear: ->
|
||||
# Calls `AppearanceChannel#appear(data)` on the server
|
||||
# Calls `AppearanceChannel#appear(data)` on the server.
|
||||
@perform("appear", appearing_on: $("main").data("appearing-on"))
|
||||
|
||||
away: ->
|
||||
# Calls `AppearanceChannel#away` on the server
|
||||
# Calls `AppearanceChannel#away` on the server.
|
||||
@perform("away")
|
||||
|
||||
|
||||
|
@ -414,13 +433,33 @@ App.cable.subscriptions.create "AppearanceChannel",
|
|||
```
|
||||
|
||||
##### Client-Server Interaction
|
||||
1. **Client** establishes a connection with the **Server** via `App.cable = ActionCable.createConsumer("ws://cable.example.com")`. [*` cable.coffee`*] The **Server** identified this connection instance by `current_user`.
|
||||
2. **Client** initiates a subscription to the `Appearance Channel` for their connection via `App.cable.subscriptions.create "AppearanceChannel"`. [*`appearance.coffee`*]
|
||||
3. **Server** recognizes a new subscription has been initiated for `AppearanceChannel` channel performs the `subscribed` callback, which calls the `appear` method on the `current_user`. [*`appearance_channel.rb`*]
|
||||
4. **Client** recognizes that a subscription has been established and calls `connected` [*`appearance.coffee`*] which in turn calls `@install` and `@appear`. `@appear` calls`AppearanceChannel#appear(data)` on the server, and supplies a data hash of `appearing_on: $("main").data("appearing-on")`. This is possible because the server-side channel instance will automatically expose the public methods declared on the class (minus the callbacks), so that these can be reached as remote procedure calls via a subscription's `perform` method.
|
||||
5. **Server** receives the request for the `appear` action on the `AppearanceChannel` channel for the connection identified by `current_user`. [*`appearance_channel.rb`*] The server retrieves the data with the `appearing_on` key from the data hash and sets it as the value for the `on:` key being passed to `current_user.appear`.
|
||||
|
||||
### Example 2: Receiving new web notifications
|
||||
1. **Client** connects to the **Server** via `App.cable =
|
||||
ActionCable.createConsumer("ws://cable.example.com")`. (`cable.js`). The
|
||||
**Server** identifies this connection by `current_user`.
|
||||
|
||||
2. **Client** subscribes to the appearance channel via
|
||||
`App.cable.subscriptions.create(channel: "AppearanceChannel")`. (`appearance.coffee`)
|
||||
|
||||
3. **Server** recognizes a new subscription has been initiated for the
|
||||
appearance channel and runs its `subscribed` callback, calling the `appear`
|
||||
method on `current_user`. (`appearance_channel.rb`)
|
||||
|
||||
4. **Client** recognizes that a subscription has been established and calls
|
||||
`connected` (`appearance.coffee`) which in turn calls `@install` and `@appear`.
|
||||
`@appear` calls `AppearanceChannel#appear(data)` on the server, and supplies a
|
||||
data hash of `{ appearing_on: $("main").data("appearing-on") }`. This is
|
||||
possible because the server-side channel instance automatically exposes all
|
||||
public methods declared on the class (minus the callbacks), so that these can be
|
||||
reached as remote procedure calls via a subscription's `perform` method.
|
||||
|
||||
5. **Server** receives the request for the `appear` action on the appearance
|
||||
channel for the connection identified by `current_user`
|
||||
(`appearance_channel.rb`). **Server** retrieves the data with the
|
||||
`:appearing_on` key from the data hash and sets it as the value for the `:on`
|
||||
key being passed to `current_user.appear`.
|
||||
|
||||
### Example 2: Receiving New Web Notifications
|
||||
|
||||
The appearance example was all about exposing server functionality to
|
||||
client-side invocation over the WebSocket connection. But the great thing
|
||||
|
@ -430,7 +469,7 @@ where the server invokes an action on the client.
|
|||
This is a web notification channel that allows you to trigger client-side
|
||||
web notifications when you broadcast to the right streams:
|
||||
|
||||
#### Create the server-side Web Notifications Channel:
|
||||
Create the server-side web notifications channel:
|
||||
|
||||
```ruby
|
||||
# app/channels/web_notifications_channel.rb
|
||||
|
@ -441,36 +480,43 @@ class WebNotificationsChannel < ApplicationCable::Channel
|
|||
end
|
||||
```
|
||||
|
||||
#### Create the client-side Web Notifications Channel subscription:
|
||||
Create the client-side web notifications channel subscription:
|
||||
|
||||
```coffeescript
|
||||
# app/assets/javascripts/cable/subscriptions/web_notifications.coffee
|
||||
# Client-side which assumes you've already requested the right to send web notifications
|
||||
# Client-side which assumes you've already requested
|
||||
# the right to send web notifications.
|
||||
App.cable.subscriptions.create "WebNotificationsChannel",
|
||||
received: (data) ->
|
||||
new Notification data["title"], body: data["body"]
|
||||
```
|
||||
|
||||
#### Broadcast content to a Web Notification Channel instance from elsewhere in your application
|
||||
Broadcast content to a web notification channel instance from elsewhere in your
|
||||
application:
|
||||
|
||||
```ruby
|
||||
# Somewhere in your app this is called, perhaps from a NewCommentJob
|
||||
WebNotificationsChannel.broadcast_to current_user, title: 'New things!', body: 'All the news fit to print'
|
||||
WebNotificationsChannel.broadcast_to(
|
||||
current_user,
|
||||
title: 'New things!',
|
||||
body: 'All the news fit to print'
|
||||
)
|
||||
```
|
||||
|
||||
The `WebNotificationsChannel.broadcast_to` call places a message in the current
|
||||
subscription adapter (Redis by default)'s pubsub queue under a separate
|
||||
broadcasting name for each user. For a user with an ID of 1, the broadcasting
|
||||
name would be `web_notifications_1`.
|
||||
subscription adapter's pubsub queue under a separate broadcasting name for each
|
||||
user. For a user with an ID of 1, the broadcasting name would be
|
||||
"web_notifications_1".
|
||||
|
||||
The channel has been instructed to stream everything that arrives at
|
||||
`web_notifications_1` directly to the client by invoking the `#received(data)`
|
||||
callback. The data is the hash sent as the second parameter to the server-side
|
||||
broadcast call, JSON encoded for the trip across the wire, and unpacked for
|
||||
the data argument arriving to `#received`.
|
||||
"web_notifications_1" directly to the client by invoking the `received`
|
||||
callback. The data passed as argument is the hash sent as the second parameter
|
||||
to the server-side broadcast call, JSON encoded for the trip across the wire,
|
||||
and unpacked for the data argument arriving to `received`.
|
||||
|
||||
### More complete examples
|
||||
### More Complete Examples
|
||||
|
||||
See the [rails/actioncable-examples](http://github.com/rails/actioncable-examples)
|
||||
See the [rails/actioncable-examples](https://github.com/rails/actioncable-examples)
|
||||
repository for a full example of how to setup Action Cable in a Rails app and adding channels.
|
||||
|
||||
## Configuration
|
||||
|
@ -479,26 +525,20 @@ Action Cable has two required configurations: a subscription adapter and allowed
|
|||
|
||||
### Subscription Adapter
|
||||
|
||||
By default, `ActionCable::Server::Base` will look for a configuration file
|
||||
in `Rails.root.join('config/cable.yml')`. The file must specify an adapter
|
||||
and a URL for each Rails environment. See the "Dependencies" section for
|
||||
additional information on adapters.
|
||||
By default, Action Cable looks for a configuration file in `config/cable.yml`.
|
||||
The file must specify an adapter and a URL for each Rails environment. See the
|
||||
[Dependencies](#dependencies) section for additional information on adapters.
|
||||
|
||||
```yaml
|
||||
production: &production
|
||||
development:
|
||||
adapter: async
|
||||
|
||||
test:
|
||||
adapter: async
|
||||
|
||||
production:
|
||||
adapter: redis
|
||||
url: redis://10.10.3.153:6381
|
||||
development: &development
|
||||
adapter: async
|
||||
test: *development
|
||||
```
|
||||
|
||||
This format allows you to specify one configuration per Rails environment.
|
||||
You can also change the location of the Action Cable config file in
|
||||
a Rails initializer with something like:
|
||||
|
||||
```ruby
|
||||
Rails.application.paths.add "config/redis/cable", with: "somewhere/else/cable.yml"
|
||||
```
|
||||
|
||||
### Allowed Request Origins
|
||||
|
@ -508,44 +548,46 @@ passed to the server config as an array. The origins can be instances of
|
|||
strings or regular expressions, against which a check for match will be performed.
|
||||
|
||||
```ruby
|
||||
Rails.application.config.action_cable.allowed_request_origins = ['http://rubyonrails.com', /http:\/\/ruby.*/]
|
||||
config.action_cable.allowed_request_origins = ['http://rubyonrails.com', %r{http://ruby.*}]
|
||||
```
|
||||
|
||||
To disable and allow requests from any origin:
|
||||
|
||||
```ruby
|
||||
Rails.application.config.action_cable.disable_request_forgery_protection = true
|
||||
config.action_cable.disable_request_forgery_protection = true
|
||||
```
|
||||
|
||||
By default, Action Cable allows all requests from localhost:3000 when running
|
||||
in the development environment.
|
||||
|
||||
|
||||
### Consumer Configuration
|
||||
|
||||
To configure the URL, add a call to `action_cable_meta_tag` in your HTML layout HEAD.
|
||||
This uses a url or path typically set via `config.action_cable.url` in the environment configuration files.
|
||||
To configure the URL, add a call to `action_cable_meta_tag` in your HTML layout
|
||||
HEAD. This uses a URL or path typically set via `config.action_cable.url` in the
|
||||
environment configuration files.
|
||||
|
||||
### Other Configurations
|
||||
|
||||
The other common option to configure is the log tags applied to the per-connection logger. Here's close to what we're using in Basecamp:
|
||||
The other common option to configure is the log tags applied to the
|
||||
per-connection logger. Here's close to what we're using in Basecamp:
|
||||
|
||||
```ruby
|
||||
Rails.application.config.action_cable.log_tags = [
|
||||
config.action_cable.log_tags = [
|
||||
-> request { request.env['bc.account_id'] || "no-account" },
|
||||
:action_cable,
|
||||
-> request { request.uuid }
|
||||
]
|
||||
```
|
||||
|
||||
For a full list of all configuration options, see the `ActionCable::Server::Configuration` class.
|
||||
For a full list of all configuration options, see the
|
||||
`ActionCable::Server::Configuration` class.
|
||||
|
||||
Also note that your server must provide at least the same number of
|
||||
database connections as you have workers. The default worker pool is
|
||||
set to 100, so that means you have to make at least that available.
|
||||
You can change that in `config/database.yml` through the `pool` attribute.
|
||||
Also note that your server must provide at least the same number of database
|
||||
connections as you have workers. The default worker pool size is set to 100, so
|
||||
that means you have to make at least that available. You can change that in
|
||||
`config/database.yml` through the `pool` attribute.
|
||||
|
||||
## Running standalone cable servers
|
||||
## Running Standalone Cable Servers
|
||||
|
||||
### In App
|
||||
|
||||
|
@ -560,30 +602,30 @@ class Application < Rails::Application
|
|||
end
|
||||
```
|
||||
|
||||
You can use `App.cable = ActionCable.createConsumer()` to connect to the
|
||||
cable server if `action_cable_meta_tag` is included in the layout. A custom
|
||||
path is specified as first argument to `createConsumer`
|
||||
(e.g. `App.cable = ActionCable.createConsumer("/websocket")`).
|
||||
You can use `App.cable = ActionCable.createConsumer()` to connect to the cable
|
||||
server if `action_cable_meta_tag` is invoked in the layout. A custom path is
|
||||
specified as first argument to `createConsumer` (e.g. `App.cable =
|
||||
ActionCable.createConsumer("/websocket")`).
|
||||
|
||||
For every instance of your server you create and for every worker
|
||||
your server spawns, you will also have a new instance of ActionCable,
|
||||
but the use of Redis keeps messages synced across connections.
|
||||
For every instance of your server you create and for every worker your server
|
||||
spawns, you will also have a new instance of Action Cable, but the use of Redis
|
||||
keeps messages synced across connections.
|
||||
|
||||
### Standalone
|
||||
|
||||
The cable servers can be separated from your normal application server.
|
||||
It's still a Rack application, but it is its own Rack application.
|
||||
The recommended basic setup is as follows:
|
||||
The cable servers can be separated from your normal application server. It's
|
||||
still a Rack application, but it is its own Rack application. The recommended
|
||||
basic setup is as follows:
|
||||
|
||||
```ruby
|
||||
# cable/config.ru
|
||||
require ::File.expand_path('../../config/environment', __FILE__)
|
||||
require_relative 'config/environment'
|
||||
Rails.application.eager_load!
|
||||
|
||||
run ActionCable.server
|
||||
```
|
||||
|
||||
Then you start the server using a binstub in bin/cable ala:
|
||||
Then you start the server using a binstub in `bin/cable` ala:
|
||||
|
||||
```
|
||||
#!/bin/bash
|
||||
|
@ -619,4 +661,5 @@ The Action Cable server implements the Rack socket hijacking API,
|
|||
thereby allowing the use of a multithreaded pattern for managing connections
|
||||
internally, irrespective of whether the application server is multi-threaded or not.
|
||||
|
||||
Accordingly, Action Cable works with all the popular application servers -- Unicorn, Puma and Passenger.
|
||||
Accordingly, Action Cable works with popular servers like Unicorn, Puma, and
|
||||
Passenger.
|
||||
|
|
|
@ -139,6 +139,10 @@
|
|||
name: Using Rails for API-only Applications
|
||||
url: api_app.html
|
||||
description: This guide explains how to effectively use Rails to develop a JSON API application.
|
||||
-
|
||||
name: Action Cable Overview
|
||||
url: action_cable_overview.html
|
||||
description: This guide explains how Action Cable works, and how to use WebSockets to create real-time features.
|
||||
|
||||
-
|
||||
name: Extending Rails
|
||||
|
|
Loading…
Reference in a new issue