Skip to content

Commit 3ff89e1

Browse files
committed
docs update
1 parent 16e0255 commit 3ff89e1

File tree

6 files changed

+170
-6
lines changed

6 files changed

+170
-6
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Optimism
22

3-
[![GitHub stars](https://img.shields.io/github/stars/leastbad/optimism?style=social)](https://github.com/leastbad/optimism) [![GitHub forks](https://img.shields.io/github/forks/leastbad/optimism?style=social)](https://github.com/leastbad/optimism) [![Twitter follow](https://img.shields.io/twitter/follow/theleastbad?style=social)](https://twitter.com/theleastbad)
3+
[![GitHub stars](https://img.shields.io/github/stars/leastbad/optimism?style=social)](https://github.com/leastbad/optimism) [![GitHub forks](https://img.shields.io/github/forks/leastbad/optimism?style=social)](https://github.com/leastbad/optimism) [![Twitter follow](https://img.shields.io/twitter/follow/theleastbad?style=social)](https://twitter.com/theleastbad) [Discord.![](https://img.shields.io/discord/681373845323513862)](https://discord.gg/GnweR3)
44

55
The missing drop-in solution for realtime remote form validation in Rails.
66

SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* [Setup](setup.md)
55
* [Quick Start](quick-start.md)
66
* [Typical Usage](typical-usage.md)
7+
* [Authentication](authentication.md)
78
* [Reference](reference.md)
89
* [Advanced Usage](advanced-usage.md)
910

authentication.md

+149
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
---
2+
description: Practice safe optimism
3+
---
4+
5+
# Authentication
6+
7+
If you're just trying to bootstrap a proof-of-concept application on your local workstation, you don't technically have to worry about giving ActionCable the ability to distinguish between multiple concurrent users. However, **the moment you deploy to a host with more than one person accessing your app, you'll find that you're sharing a session and seeing other people's updates**. That isn't what most developers have in mind.
8+
9+
## Encrypted Session Cookies
10+
11+
You can use your default Rails encrypted cookie-based sessions to isolate your users into their own sessions. This works great even if your application doesn't have a login system.
12+
13+
{% code title="app/controllers/application\_controller.rb" %}
14+
```ruby
15+
class ApplicationController < ActionController::Base
16+
before_action :set_action_cable_identifier
17+
18+
private
19+
20+
def set_action_cable_identifier
21+
cookies.encrypted[:session_id] = session.id.to_s
22+
end
23+
end
24+
```
25+
{% endcode %}
26+
27+
{% code title="app/channels/application\_cable/connection.rb" %}
28+
```ruby
29+
module ApplicationCable
30+
class Connection < ActionCable::Connection::Base
31+
identified_by :session_id
32+
33+
def connect
34+
self.session_id = cookies.encrypted[:session_id]
35+
end
36+
end
37+
end
38+
```
39+
{% endcode %}
40+
41+
We need to instruct ActionCable to stream updates on a per-session basis:
42+
43+
{% code title="app/channels/optimism_channel.rb" %}
44+
```ruby
45+
class OptimismChannel < ApplicationCable::Channel
46+
def subscribed
47+
stream_for session_id
48+
end
49+
end
50+
```
51+
{% endcode %}
52+
53+
Finally, we need to give Optimism the ability to broadcast updates to the correct channel subscription. We will override Optimism's default "OptimismChannel" with a lambda that returns the subscription identifier. You might already have other values in your initializer, or it might not yet exist at all:
54+
55+
{% code title="config/initializers/optimism.rb" %}
56+
```ruby
57+
Optimism.configure do |config|
58+
config.channel = ->(context) { OptimismChannel.broadcasting_for(context.session.id) }
59+
end
60+
```
61+
{% endcode %}
62+
63+
## User-based Authentication
64+
65+
Many Rails apps use the current\_user convention or more recently, the [Current](https://api.rubyonrails.org/classes/ActiveSupport/CurrentAttributes.html) object to provide a global user context. This gives access to the user scope from _almost_ all parts of your application.
66+
67+
{% code title="app/controllers/application\_controller.rb " %}
68+
```ruby
69+
class ApplicationController < ActionController::Base
70+
before_action :set_action_cable_identifier
71+
72+
private
73+
74+
def set_action_cable_identifier
75+
cookies.encrypted[:user_id] = current_user&.id
76+
end
77+
end
78+
```
79+
{% endcode %}
80+
81+
{% code title="app/channels/application\_cable/connection.rb " %}
82+
```ruby
83+
module ApplicationCable
84+
class Connection < ActionCable::Connection::Base
85+
identified_by :current_user
86+
87+
def connect
88+
user_id = cookies.encrypted[:user_id]
89+
return reject_unauthorized_connection if user_id.nil?
90+
user = User.find_by(id: user_id)
91+
return reject_unauthorized_connection if user.nil?
92+
self.current_user = user
93+
end
94+
end
95+
end
96+
```
97+
{% endcode %}
98+
99+
We need to instruct ActionCable to stream updates on a per-session basis:
100+
101+
{% code title="app/channels/optimism_channel.rb" %}
102+
```ruby
103+
class OptimismChannel < ApplicationCable::Channel
104+
def subscribed
105+
stream_for current_user
106+
end
107+
end
108+
```
109+
{% endcode %}
110+
111+
Finally, we need to give Optimism the ability to broadcast updates to the correct channel subscription. We will override Optimism's default "OptimismChannel" with a lambda that returns the subscription identifier. You might already have other values in your initializer, or it might not yet exist at all:
112+
113+
{% code title="config/initializers/optimism.rb" %}
114+
```ruby
115+
Optimism.configure do |config|
116+
config.channel = ->(context) { OptimismChannel.broadcasting_for(context.current_user) }
117+
end
118+
```
119+
{% endcode %}
120+
121+
## Devise-based Authentication
122+
123+
If you're using the versatile [Devise](https://github.com/plataformatec/devise) authentication library, your configuration is *identical* to the User-Based Authentication above, **except** for how ActionCable looks up a user:
124+
125+
{% code title="app/channels/application\_cable/connection.rb" %}
126+
```ruby
127+
module ApplicationCable
128+
class Connection < ActionCable::Connection::Base
129+
identified_by :current_user
130+
131+
def connect
132+
self.current_user = find_verified_user
133+
end
134+
135+
protected
136+
137+
def find_verified_user
138+
if current_user = env["warden"].user
139+
current_user
140+
else
141+
reject_unauthorized_connection
142+
end
143+
end
144+
end
145+
end
146+
```
147+
{% endcode %}
148+
149+

lib/templates/optimism_channel.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
class OptimismChannel < ApplicationCable::Channel
22
def subscribed
3-
stream_for current_user
3+
stream_from "OptimismChannel"
44
end
55
end

reference.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ Optimism is configurable via an optional initializer file. As with all initializ
9393
{% code title="config/initializers/optimism.rb" %}
9494
```ruby
9595
Optimism.configure do |config|
96-
config.channel = "OptimismChannel"
96+
config.channel = ->(context) { "OptimismChannel" }
9797
config.form_class = "invalid"
9898
config.error_class = "error"
9999
config.disable_submit = false
@@ -109,7 +109,7 @@ end
109109
```
110110
{% endcode %}
111111

112-
**channel**: The ActionCable channel created by the `rake optimism:install` setup task. In most cases, you don't need to change this value. In fact, the only good reason to change this value is if you already have an OptimismChannel. If this describes you, congratulations on your optimism.
112+
**channel**: The ActionCable channel created by the `rake optimism:install` setup task. Good enough to get you up and running in development, you will need to pull your desired identifier from the context Optimism is running in and let the `broadcasting_for` method on `OptimismChannel` call the shots. Find out more on the [authentication](https://optimism.leastbad.com/authentication) page.
113113

114114
**form\_class**: The CSS class that will be applied to the form if the id has been properly set eg. `posts_form` \(following the simple pattern **resources\_form**\). If form\_class is set to false or nil, no CSS class will be applied.
115115

setup.md

+16-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,21 @@ The terminal commands above will ensure that Optimism is installed. It creates t
1818

1919
![](.gitbook/assets/setup.svg)
2020

21-
### Logging
21+
# Authentication
22+
23+
{% hint style="info" %}
24+
If you're just experimenting with Optimism or trying to bootstrap a proof-of-concept application on your local workstation, you can actually skip this section until you're planning to deploy.
25+
{% endhint %}
26+
27+
Out of the box, ActionCable doesn't give Optimism the ability to distinguish between multiple concurrent users looking at the same page.
28+
29+
**If you deploy to a host with more than one person accessing your app, you'll find that you're sharing a session and seeing other people's updates.** That isn't what most developers have in mind!
30+
31+
When the time comes, it's easy to configure your application to support authenticating users by their Rails session or current_user scope. Just check out the Authentication page and choose your own adventure.
32+
33+
{% page-ref page="authentication.md" %}
34+
35+
# Logging
2236

2337
In the default _debug_ log level, ActionCable emits particularly verbose log messages. You can optionally discard everything but exceptions by switching to the _warn_ log level, as is common in development environments:
2438

@@ -29,7 +43,7 @@ config.log_level = :warn
2943
```
3044
{% endcode %}
3145

32-
### Troubleshooting
46+
# Troubleshooting
3347

3448
{% hint style="info" %}
3549
If _something_ goes wrong, it's often because of the **spring** gem. You can test this by temporarily setting the `DISABLE_SPRING=1` environment variable and restarting your server.

0 commit comments

Comments
 (0)