optimism 0.2.12 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d4847fe08861efa42698ce30c5c1d7a52b31007c61be8b9bb9b23058c170d4c1
4
- data.tar.gz: 69e2910e1a91580516a98f051ef5589d1836cdf6f5bce0dd7222cc211ccaa383
3
+ metadata.gz: 86be504b270b8c5ec388d09a1bdceaf7a415becb0847e911cd0a4f31ed756145
4
+ data.tar.gz: 351510dbb07f54523d3bf16e2c9412f1c9c9edd8423dfa371713d49988936765
5
5
  SHA512:
6
- metadata.gz: ea79b92e27f01f7b9956d9af05f6a3f5abb474f16d919aa1c034b984a74fd7bf90bfb5874b42f10774bb0caf3864853a20bfe3d271010a5510d5f885395e58b9
7
- data.tar.gz: 7102ad961b9f4052639422f616237be25ffa4e5ac132807c1be50a42aa46c3d0015fecb063a1eadd89e7fcb552bc3d363fcf55b55b713514ab2414e3a5fd5303
6
+ metadata.gz: 89dd0cfe1095d4d1a63233195e2d9c69ab04298995406f3e035880cfd81d531a9b0407204ad875867340f0a3e03e5d5ac8bb286dd90dd47bd0b3e895d209cc6c
7
+ data.tar.gz: 11721e72984cbeeae273a9a5096a4b743b21415b2bb5ef543cb00cb0059841b1522b6cf9ff6b22aeebb8fb3324026833b64399aee6f38749e63e0bd2944c9016
@@ -1,72 +1,72 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- optimism (0.2.10)
5
- cable_ready (~> 4.0.9)
6
- rack
7
- rails (>= 5.2)
4
+ optimism (0.3.1)
5
+ cable_ready (>= 4)
6
+ rack (~> 2.0)
7
+ rails (>= 6, >= 5.2)
8
8
 
9
9
  GEM
10
10
  remote: https://rubygems.org/
11
11
  specs:
12
- actioncable (6.0.2.2)
13
- actionpack (= 6.0.2.2)
12
+ actioncable (6.0.3.1)
13
+ actionpack (= 6.0.3.1)
14
14
  nio4r (~> 2.0)
15
15
  websocket-driver (>= 0.6.1)
16
- actionmailbox (6.0.2.2)
17
- actionpack (= 6.0.2.2)
18
- activejob (= 6.0.2.2)
19
- activerecord (= 6.0.2.2)
20
- activestorage (= 6.0.2.2)
21
- activesupport (= 6.0.2.2)
16
+ actionmailbox (6.0.3.1)
17
+ actionpack (= 6.0.3.1)
18
+ activejob (= 6.0.3.1)
19
+ activerecord (= 6.0.3.1)
20
+ activestorage (= 6.0.3.1)
21
+ activesupport (= 6.0.3.1)
22
22
  mail (>= 2.7.1)
23
- actionmailer (6.0.2.2)
24
- actionpack (= 6.0.2.2)
25
- actionview (= 6.0.2.2)
26
- activejob (= 6.0.2.2)
23
+ actionmailer (6.0.3.1)
24
+ actionpack (= 6.0.3.1)
25
+ actionview (= 6.0.3.1)
26
+ activejob (= 6.0.3.1)
27
27
  mail (~> 2.5, >= 2.5.4)
28
28
  rails-dom-testing (~> 2.0)
29
- actionpack (6.0.2.2)
30
- actionview (= 6.0.2.2)
31
- activesupport (= 6.0.2.2)
29
+ actionpack (6.0.3.1)
30
+ actionview (= 6.0.3.1)
31
+ activesupport (= 6.0.3.1)
32
32
  rack (~> 2.0, >= 2.0.8)
33
33
  rack-test (>= 0.6.3)
34
34
  rails-dom-testing (~> 2.0)
35
35
  rails-html-sanitizer (~> 1.0, >= 1.2.0)
36
- actiontext (6.0.2.2)
37
- actionpack (= 6.0.2.2)
38
- activerecord (= 6.0.2.2)
39
- activestorage (= 6.0.2.2)
40
- activesupport (= 6.0.2.2)
36
+ actiontext (6.0.3.1)
37
+ actionpack (= 6.0.3.1)
38
+ activerecord (= 6.0.3.1)
39
+ activestorage (= 6.0.3.1)
40
+ activesupport (= 6.0.3.1)
41
41
  nokogiri (>= 1.8.5)
42
- actionview (6.0.2.2)
43
- activesupport (= 6.0.2.2)
42
+ actionview (6.0.3.1)
43
+ activesupport (= 6.0.3.1)
44
44
  builder (~> 3.1)
45
45
  erubi (~> 1.4)
46
46
  rails-dom-testing (~> 2.0)
47
47
  rails-html-sanitizer (~> 1.1, >= 1.2.0)
48
- activejob (6.0.2.2)
49
- activesupport (= 6.0.2.2)
48
+ activejob (6.0.3.1)
49
+ activesupport (= 6.0.3.1)
50
50
  globalid (>= 0.3.6)
51
- activemodel (6.0.2.2)
52
- activesupport (= 6.0.2.2)
53
- activerecord (6.0.2.2)
54
- activemodel (= 6.0.2.2)
55
- activesupport (= 6.0.2.2)
56
- activestorage (6.0.2.2)
57
- actionpack (= 6.0.2.2)
58
- activejob (= 6.0.2.2)
59
- activerecord (= 6.0.2.2)
51
+ activemodel (6.0.3.1)
52
+ activesupport (= 6.0.3.1)
53
+ activerecord (6.0.3.1)
54
+ activemodel (= 6.0.3.1)
55
+ activesupport (= 6.0.3.1)
56
+ activestorage (6.0.3.1)
57
+ actionpack (= 6.0.3.1)
58
+ activejob (= 6.0.3.1)
59
+ activerecord (= 6.0.3.1)
60
60
  marcel (~> 0.3.1)
61
- activesupport (6.0.2.2)
61
+ activesupport (6.0.3.1)
62
62
  concurrent-ruby (~> 1.0, >= 1.0.2)
63
63
  i18n (>= 0.7, < 2)
64
64
  minitest (~> 5.1)
65
65
  tzinfo (~> 1.1)
66
- zeitwerk (~> 2.2)
66
+ zeitwerk (~> 2.2, >= 2.2.2)
67
67
  ast (2.4.0)
68
68
  builder (3.2.4)
69
- cable_ready (4.0.9)
69
+ cable_ready (4.1.2)
70
70
  rails (>= 5.2)
71
71
  coderay (1.1.2)
72
72
  concurrent-ruby (1.1.6)
@@ -77,7 +77,7 @@ GEM
77
77
  i18n (1.8.2)
78
78
  concurrent-ruby (~> 1.0)
79
79
  jaro_winkler (1.5.4)
80
- loofah (2.4.0)
80
+ loofah (2.5.0)
81
81
  crass (~> 1.0.2)
82
82
  nokogiri (>= 1.5.9)
83
83
  mail (2.7.1)
@@ -85,10 +85,10 @@ GEM
85
85
  marcel (0.3.3)
86
86
  mimemagic (~> 0.3.2)
87
87
  method_source (0.9.2)
88
- mimemagic (0.3.4)
88
+ mimemagic (0.3.5)
89
89
  mini_mime (1.0.2)
90
90
  mini_portile2 (2.4.0)
91
- minitest (5.14.0)
91
+ minitest (5.14.1)
92
92
  nio4r (2.5.2)
93
93
  nokogiri (1.10.9)
94
94
  mini_portile2 (~> 2.4.0)
@@ -103,29 +103,29 @@ GEM
103
103
  rack (2.2.2)
104
104
  rack-test (1.1.0)
105
105
  rack (>= 1.0, < 3)
106
- rails (6.0.2.2)
107
- actioncable (= 6.0.2.2)
108
- actionmailbox (= 6.0.2.2)
109
- actionmailer (= 6.0.2.2)
110
- actionpack (= 6.0.2.2)
111
- actiontext (= 6.0.2.2)
112
- actionview (= 6.0.2.2)
113
- activejob (= 6.0.2.2)
114
- activemodel (= 6.0.2.2)
115
- activerecord (= 6.0.2.2)
116
- activestorage (= 6.0.2.2)
117
- activesupport (= 6.0.2.2)
106
+ rails (6.0.3.1)
107
+ actioncable (= 6.0.3.1)
108
+ actionmailbox (= 6.0.3.1)
109
+ actionmailer (= 6.0.3.1)
110
+ actionpack (= 6.0.3.1)
111
+ actiontext (= 6.0.3.1)
112
+ actionview (= 6.0.3.1)
113
+ activejob (= 6.0.3.1)
114
+ activemodel (= 6.0.3.1)
115
+ activerecord (= 6.0.3.1)
116
+ activestorage (= 6.0.3.1)
117
+ activesupport (= 6.0.3.1)
118
118
  bundler (>= 1.3.0)
119
- railties (= 6.0.2.2)
119
+ railties (= 6.0.3.1)
120
120
  sprockets-rails (>= 2.0.0)
121
121
  rails-dom-testing (2.0.3)
122
122
  activesupport (>= 4.2.0)
123
123
  nokogiri (>= 1.6)
124
124
  rails-html-sanitizer (1.3.0)
125
125
  loofah (~> 2.3)
126
- railties (6.0.2.2)
127
- actionpack (= 6.0.2.2)
128
- activesupport (= 6.0.2.2)
126
+ railties (6.0.3.1)
127
+ actionpack (= 6.0.3.1)
128
+ activesupport (= 6.0.3.1)
129
129
  method_source
130
130
  rake (>= 0.8.7)
131
131
  thor (>= 0.20.3, < 2.0)
@@ -155,12 +155,12 @@ GEM
155
155
  standard
156
156
  thor (1.0.1)
157
157
  thread_safe (0.3.6)
158
- tzinfo (1.2.6)
158
+ tzinfo (1.2.7)
159
159
  thread_safe (~> 0.1)
160
160
  unicode-display_width (1.6.1)
161
161
  websocket-driver (0.7.1)
162
162
  websocket-extensions (>= 0.1.0)
163
- websocket-extensions (0.1.4)
163
+ websocket-extensions (0.1.5)
164
164
  zeitwerk (2.3.0)
165
165
 
166
166
  PLATFORMS
@@ -169,10 +169,10 @@ PLATFORMS
169
169
  DEPENDENCIES
170
170
  bundler (~> 2.0)
171
171
  optimism!
172
- pry
173
- pry-nav
172
+ pry (~> 0.12.2)
173
+ pry-nav (~> 0.3.0)
174
174
  rake (~> 13.0)
175
- standardrb
175
+ standardrb (~> 1.0.0)
176
176
 
177
177
  BUNDLED WITH
178
- 2.0.2
178
+ 2.1.4
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Optimism
2
2
 
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)
4
4
 
5
5
  The missing drop-in solution for realtime remote form validation in Rails.
6
6
 
@@ -8,7 +8,7 @@ The missing drop-in solution for realtime remote form validation in Rails.
8
8
 
9
9
  [Optimism](https://github.com/leastbad/optimism) is an MIT-licensed [Ruby on Rails](https://rubyonrails.org/) gem that makes it easy to give your users instant constructive feedback if they enter invalid data into your application. Instead of dumping a list of errors at the top of your interface, Optimism provides specific instructions directly beside or below individual input elements.
10
10
 
11
- You can try a [live demo](https://optimism-demo.herokuapp.com) right now.
11
+ You can try a 👉 [live demo](https://optimism-demo.herokuapp.com) 👈 right now.
12
12
 
13
13
  ![](.gitbook/assets/fill_forms.svg)
14
14
 
data/SUMMARY.md CHANGED
@@ -4,6 +4,7 @@
4
4
  * [Setup](setup.md)
5
5
  * [Quick Start](quick-start.md)
6
6
  * [Typical Usage](typical-usage.md)
7
+ * [Authentication](authentication.md)
7
8
  * [Reference](reference.md)
8
9
  * [Advanced Usage](advanced-usage.md)
9
10
 
@@ -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
+
@@ -6,7 +6,7 @@ module Optimism
6
6
  include CableReady::Broadcaster
7
7
  class << self
8
8
  mattr_accessor :channel, :form_class, :error_class, :disable_submit, :suffix, :emit_events, :add_css, :inject_inline, :container_selector, :error_selector, :form_selector, :submit_selector
9
- self.channel = "OptimismChannel"
9
+ self.channel = ->(context) { "OptimismChannel" }
10
10
  self.form_class = "invalid"
11
11
  self.error_class = "error"
12
12
  self.disable_submit = false
@@ -26,39 +26,44 @@ module Optimism
26
26
 
27
27
  def broadcast_errors(model, attributes)
28
28
  return unless model&.errors&.messages
29
- resource = model.class.to_s.downcase
29
+ resource = model.class.to_s.underscore
30
30
  form_selector, submit_selector = Optimism.form_selector.sub("RESOURCE", resource), Optimism.submit_selector.sub("RESOURCE", resource)
31
31
  attributes = case attributes
32
32
  when ActionController::Parameters, Hash, ActiveSupport::HashWithIndifferentAccess
33
- attributes.to_h.keys
33
+ attributes.to_h
34
34
  when String, Symbol
35
- [attributes.to_s]
35
+ { attributes.to_s => nil }
36
36
  when Array
37
- attributes.flatten.map &:to_s
37
+ attributes.flatten.each.with_object({}) { |attr, obj| obj[attr.to_s] = nil }
38
38
  else
39
39
  raise Exception.new "attributes must be a Hash (Parameters, Indifferent or standard), Array, Symbol or String"
40
40
  end
41
+ model.valid? if model.errors.empty?
41
42
  process_resource(model, attributes, [resource])
42
43
  if model.errors.any?
43
- cable_ready[Optimism.channel].dispatch_event(name: "optimism:form:invalid", detail: {resource: resource}) if Optimism.emit_events
44
- cable_ready[Optimism.channel].add_css_class(selector: form_selector, name: Optimism.form_class) if Optimism.form_class.present?
45
- cable_ready[Optimism.channel].set_attribute(selector: submit_selector, name: "disabled") if Optimism.disable_submit
44
+ cable_ready[Optimism.channel[self]].dispatch_event(name: "optimism:form:invalid", detail: {resource: resource}) if Optimism.emit_events
45
+ cable_ready[Optimism.channel[self]].add_css_class(selector: form_selector, name: Optimism.form_class) if Optimism.form_class.present?
46
+ cable_ready[Optimism.channel[self]].set_attribute(selector: submit_selector, name: "disabled") if Optimism.disable_submit
46
47
  else
47
- cable_ready[Optimism.channel].dispatch_event(name: "optimism:form:valid", detail: {resource: resource}) if Optimism.emit_events
48
- cable_ready[Optimism.channel].remove_css_class(selector: form_selector, name: Optimism.form_class) if Optimism.form_class.present?
49
- cable_ready[Optimism.channel].remove_attribute(selector: submit_selector, name: "disabled") if Optimism.disable_submit
48
+ cable_ready[Optimism.channel[self]].dispatch_event(name: "optimism:form:valid", detail: {resource: resource}) if Optimism.emit_events
49
+ cable_ready[Optimism.channel[self]].remove_css_class(selector: form_selector, name: Optimism.form_class) if Optimism.form_class.present?
50
+ cable_ready[Optimism.channel[self]].remove_attribute(selector: submit_selector, name: "disabled") if Optimism.disable_submit
50
51
  end
51
52
  cable_ready.broadcast
52
- head :ok
53
+ head :ok if defined?(head)
53
54
  end
54
55
 
55
56
  def process_resource(model, attributes, ancestry)
56
- attributes.each do |attribute|
57
+ attributes.keys.each do |attribute|
57
58
  if attribute.ends_with?("_attributes")
58
59
  resource = attribute[0..-12]
59
- nested_models = model.send(resource.to_sym)
60
- nested_models.each_with_index do |nested, index|
61
- process_resource(nested, attributes[attribute][index.to_s], ancestry + [resource, index]) if attributes[attribute].key?(index.to_s)
60
+ association = model.send(resource.to_sym)
61
+ if association.respond_to? :each_with_index
62
+ association.each_with_index do |nested, index|
63
+ process_resource(nested, attributes[attribute][index.to_s], ancestry + [resource, index]) if attributes[attribute].key?(index.to_s)
64
+ end
65
+ else
66
+ process_resource(association, attributes[attribute], ancestry + [resource])
62
67
  end
63
68
  else
64
69
  process_attribute(model, attribute, ancestry.dup)
@@ -68,17 +73,21 @@ module Optimism
68
73
 
69
74
  def process_attribute(model, attribute, ancestry)
70
75
  resource = ancestry.shift
71
- resource += "_#{ancestry.shift}_attributes_#{ancestry.shift}" until ancestry.empty?
76
+ if ancestry.size == 1
77
+ resource += "_#{ancestry.shift}_attributes"
78
+ else
79
+ resource += "_#{ancestry.shift}_attributes_#{ancestry.shift}" until ancestry.empty?
80
+ end
72
81
  container_selector, error_selector = Optimism.container_selector.sub("RESOURCE", resource).sub("ATTRIBUTE", attribute), Optimism.error_selector.sub("RESOURCE", resource).sub("ATTRIBUTE", attribute)
73
- if model.errors.messages.map(&:first).include?(attribute.to_sym)
74
- message = "#{model.errors.full_message(attribute.humanize, model.errors.messages[attribute.to_sym].first)}#{Optimism.suffix}"
75
- cable_ready[Optimism.channel].dispatch_event(name: "optimism:attribute:invalid", detail: {resource: resource, attribute: attribute, text: message}) if Optimism.emit_events
76
- cable_ready[Optimism.channel].add_css_class(selector: container_selector, name: Optimism.error_class) if Optimism.add_css
77
- cable_ready[Optimism.channel].text_content(selector: error_selector, text: message) if Optimism.inject_inline
82
+ if model.errors.any? && model.errors.messages.map(&:first).include?(attribute.to_sym)
83
+ message = "#{model.errors.full_message(attribute.to_sym, model.errors.messages[attribute.to_sym].first)}#{Optimism.suffix}"
84
+ cable_ready[Optimism.channel[self]].dispatch_event(name: "optimism:attribute:invalid", detail: {resource: resource, attribute: attribute, text: message}) if Optimism.emit_events
85
+ cable_ready[Optimism.channel[self]].add_css_class(selector: container_selector, name: Optimism.error_class) if Optimism.add_css
86
+ cable_ready[Optimism.channel[self]].text_content(selector: error_selector, text: message) if Optimism.inject_inline
78
87
  else
79
- cable_ready[Optimism.channel].dispatch_event(name: "optimism:attribute:valid", detail: {resource: resource, attribute: attribute}) if Optimism.emit_events
80
- cable_ready[Optimism.channel].remove_css_class(selector: container_selector, name: Optimism.error_class) if Optimism.add_css
81
- cable_ready[Optimism.channel].text_content(selector: error_selector, text: "") if Optimism.inject_inline
88
+ cable_ready[Optimism.channel[self]].dispatch_event(name: "optimism:attribute:valid", detail: {resource: resource, attribute: attribute}) if Optimism.emit_events
89
+ cable_ready[Optimism.channel[self]].remove_css_class(selector: container_selector, name: Optimism.error_class) if Optimism.add_css
90
+ cable_ready[Optimism.channel[self]].text_content(selector: error_selector, text: "") if Optimism.inject_inline
82
91
  end
83
92
  end
84
93
  end
@@ -90,7 +99,7 @@ module ActionView::Helpers
90
99
  end
91
100
 
92
101
  def container_id_for(attribute)
93
- Optimism.container_selector.sub("RESOURCE", object_name.delete("]").tr("[", "_")).sub("ATTRIBUTE", attribute.to_s)[1..-1]
102
+ Optimism.container_selector.sub("RESOURCE", object_name.to_s.delete("]").tr("[", "_")).sub("ATTRIBUTE", attribute.to_s)[1..-1]
94
103
  end
95
104
 
96
105
  def error_for(attribute, **options)
@@ -98,7 +107,7 @@ module ActionView::Helpers
98
107
  end
99
108
 
100
109
  def error_id_for(attribute)
101
- Optimism.error_selector.sub("RESOURCE", object_name.delete("]").tr("[", "_")).sub("ATTRIBUTE", attribute.to_s)[1..-1]
110
+ Optimism.error_selector.sub("RESOURCE", object_name.to_s.delete("]").tr("[", "_")).sub("ATTRIBUTE", attribute.to_s)[1..-1]
102
111
  end
103
112
  end
104
113
  end
@@ -1,3 +1,3 @@
1
1
  module Optimism
2
- VERSION = "0.2.12"
2
+ VERSION = "0.3.3"
3
3
  end
@@ -20,12 +20,12 @@ Gem::Specification.new do |spec|
20
20
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
21
  spec.require_paths = ["lib"]
22
22
 
23
- spec.add_development_dependency "bundler", ">= 2.0"
24
- spec.add_development_dependency "rake", ">= 13.0"
25
- spec.add_development_dependency "pry", ">= 0.12.2"
26
- spec.add_development_dependency "pry-nav", ">= 0.3.0"
27
- spec.add_development_dependency "standardrb", ">= 1.0.0"
28
- spec.add_dependency "rack", ">= 2.0"
29
- spec.add_dependency "rails", ">= 5.2"
30
- spec.add_dependency "cable_ready", ">= 4.1"
23
+ spec.add_development_dependency "bundler", "~> 2.0"
24
+ spec.add_development_dependency "rake", "~> 13.0"
25
+ spec.add_development_dependency "pry", "~> 0.12.2"
26
+ spec.add_development_dependency "pry-nav", "~> 0.3.0"
27
+ spec.add_development_dependency "standardrb", "~> 1.0.0"
28
+ spec.add_dependency "rack", "~> 2.0"
29
+ spec.add_dependency "rails", [">= 5.2", ">= 6"]
30
+ spec.add_dependency "cable_ready", ">= 4"
31
31
  end
@@ -93,7 +93,7 @@ Optimism is configurable via an optional initializer file. As with all initializ
93
93
  {% code title="config/initializers/optimism.rb" %}
94
94
  ```ruby
95
95
  Optimism.configure do |config|
96
- config.channel = "OptimismChannel"
96
+ config.channel = ->(context) { "OptimismChannel" }
97
97
  config.form_class = "invalid"
98
98
  config.error_class = "error"
99
99
  config.disable_submit = false
@@ -109,7 +109,7 @@ end
109
109
  ```
110
110
  {% endcode %}
111
111
 
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.
113
113
 
114
114
  **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.
115
115
 
data/setup.md CHANGED
@@ -18,7 +18,21 @@ The terminal commands above will ensure that Optimism is installed. It creates t
18
18
 
19
19
  ![](.gitbook/assets/setup.svg)
20
20
 
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
22
36
 
23
37
  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:
24
38
 
@@ -29,7 +43,7 @@ config.log_level = :warn
29
43
  ```
30
44
  {% endcode %}
31
45
 
32
- ### Troubleshooting
46
+ # Troubleshooting
33
47
 
34
48
  {% hint style="info" %}
35
49
  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.
metadata CHANGED
@@ -1,97 +1,97 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: optimism
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.12
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - leastbad
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-04-06 00:00:00.000000000 Z
11
+ date: 2020-06-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '2.0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '13.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '13.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: pry
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
47
  version: 0.12.2
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: 0.12.2
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: pry-nav
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
61
  version: 0.3.0
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ">="
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: 0.3.0
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: standardrb
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ">="
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
75
  version: 1.0.0
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ">="
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: 1.0.0
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rack
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ">="
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
89
  version: '2.0'
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ">="
94
+ - - "~>"
95
95
  - !ruby/object:Gem::Version
96
96
  version: '2.0'
97
97
  - !ruby/object:Gem::Dependency
@@ -101,6 +101,9 @@ dependencies:
101
101
  - - ">="
102
102
  - !ruby/object:Gem::Version
103
103
  version: '5.2'
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: '6'
104
107
  type: :runtime
105
108
  prerelease: false
106
109
  version_requirements: !ruby/object:Gem::Requirement
@@ -108,20 +111,23 @@ dependencies:
108
111
  - - ">="
109
112
  - !ruby/object:Gem::Version
110
113
  version: '5.2'
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '6'
111
117
  - !ruby/object:Gem::Dependency
112
118
  name: cable_ready
113
119
  requirement: !ruby/object:Gem::Requirement
114
120
  requirements:
115
121
  - - ">="
116
122
  - !ruby/object:Gem::Version
117
- version: '4.1'
123
+ version: '4'
118
124
  type: :runtime
119
125
  prerelease: false
120
126
  version_requirements: !ruby/object:Gem::Requirement
121
127
  requirements:
122
128
  - - ">="
123
129
  - !ruby/object:Gem::Version
124
- version: '4.1'
130
+ version: '4'
125
131
  description: Realtime remote form input validations delivered via websockets
126
132
  email:
127
133
  - hello@leastbad.com
@@ -148,6 +154,7 @@ files:
148
154
  - Rakefile
149
155
  - SUMMARY.md
150
156
  - advanced-usage.md
157
+ - authentication.md
151
158
  - bin/console
152
159
  - bin/loc
153
160
  - bin/setup