stimulus_reflex 3.4.0.pre6 → 3.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of stimulus_reflex might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +96 -8
- data/CODE_OF_CONDUCT.md +6 -0
- data/Gemfile.lock +92 -85
- data/README.md +6 -5
- data/app/channels/stimulus_reflex/channel.rb +24 -2
- data/lib/generators/stimulus_reflex/templates/app/reflexes/%file_name%_reflex.rb.tt +1 -0
- data/lib/generators/stimulus_reflex/templates/config/initializers/stimulus_reflex.rb +10 -1
- data/lib/stimulus_reflex.rb +2 -1
- data/lib/stimulus_reflex/broadcasters/page_broadcaster.rb +1 -0
- data/lib/stimulus_reflex/cable_ready_channels.rb +16 -6
- data/lib/stimulus_reflex/callbacks.rb +48 -0
- data/lib/stimulus_reflex/configuration.rb +2 -1
- data/lib/stimulus_reflex/logger.rb +6 -6
- data/lib/stimulus_reflex/reflex.rb +31 -45
- data/lib/stimulus_reflex/sanity_checker.rb +7 -0
- data/lib/stimulus_reflex/version.rb +1 -1
- data/lib/tasks/stimulus_reflex/install.rake +8 -3
- data/package.json +3 -3
- data/stimulus_reflex.gemspec +3 -1
- data/tags +30 -13
- data/test/broadcasters/broadcaster_test.rb +2 -0
- data/test/broadcasters/broadcaster_test_case.rb +2 -0
- data/test/broadcasters/nothing_broadcaster_test.rb +2 -0
- data/test/broadcasters/page_broadcaster_test.rb +2 -0
- data/test/broadcasters/selector_broadcaster_test.rb +2 -0
- data/test/reflex_test.rb +32 -0
- data/test/test_helper.rb +6 -0
- data/test/tmp/app/reflexes/application_reflex.rb +1 -1
- data/test/tmp/app/reflexes/{demo_reflex.rb → user_reflex.rb} +10 -1
- data/yarn.lock +279 -303
- metadata +12 -9
@@ -40,8 +40,8 @@ class StimulusReflex::Channel < StimulusReflex.configuration.parent_channel.cons
|
|
40
40
|
params: params,
|
41
41
|
client_attributes: {
|
42
42
|
reflex_id: data["reflexId"],
|
43
|
-
|
44
|
-
|
43
|
+
xpath_controller: data["xpathController"],
|
44
|
+
xpath_element: data["xpathElement"],
|
45
45
|
reflex_controller: data["reflexController"],
|
46
46
|
permanent_attribute_name: permanent_attribute_name
|
47
47
|
})
|
@@ -49,11 +49,33 @@ class StimulusReflex::Channel < StimulusReflex.configuration.parent_channel.cons
|
|
49
49
|
rescue => invoke_error
|
50
50
|
message = exception_message_with_backtrace(invoke_error)
|
51
51
|
body = "Reflex #{target} failed: #{message} [#{url}]"
|
52
|
+
|
52
53
|
if reflex
|
53
54
|
reflex.rescue_with_handler(invoke_error)
|
54
55
|
reflex.broadcast_message subject: "error", body: body, data: data, error: invoke_error
|
55
56
|
else
|
56
57
|
puts "\e[31m#{body}\e[0m"
|
58
|
+
|
59
|
+
if body.to_s.include? "No route matches"
|
60
|
+
initializer_path = Rails.root.join("config", "initializers", "stimulus_reflex.rb")
|
61
|
+
|
62
|
+
puts <<~NOTE
|
63
|
+
\e[33mNOTE: StimulusReflex failed to locate a matching route and could not re-render the page.
|
64
|
+
|
65
|
+
If your app uses Rack middleware to rewrite part of the request path, you must enable those middleware modules in StimulusReflex.
|
66
|
+
The StimulusReflex initializer should be located at #{initializer_path}, or you can generate it with:
|
67
|
+
|
68
|
+
$ bundle exec rails generate stimulus_reflex:config
|
69
|
+
|
70
|
+
Configure any required middleware:
|
71
|
+
|
72
|
+
StimulusReflex.configure do |config|
|
73
|
+
config.middleware.use FirstRackMiddleware
|
74
|
+
config.middleware.use SecondRackMiddleware
|
75
|
+
end\e[0m
|
76
|
+
|
77
|
+
NOTE
|
78
|
+
end
|
57
79
|
end
|
58
80
|
return
|
59
81
|
end
|
@@ -16,6 +16,7 @@ class <%= class_name %>Reflex < ApplicationReflex
|
|
16
16
|
# - signed - use a signed Global ID to map dataset attribute to a model eg. element.signed[:foo]
|
17
17
|
# - unsigned - use an unsigned Global ID to map dataset attribute to a model eg. element.unsigned[:foo]
|
18
18
|
# - cable_ready - a special cable_ready that can broadcast to the current visitor (no brackets needed)
|
19
|
+
# - reflex_id - a UUIDv4 that uniquely identies each Reflex
|
19
20
|
#
|
20
21
|
# Example:
|
21
22
|
#
|
@@ -12,9 +12,18 @@ StimulusReflex.configure do |config|
|
|
12
12
|
|
13
13
|
# Customize server-side Reflex logging format, with optional colorization:
|
14
14
|
# Available tokens: session_id, session_id_full, reflex_info, operation, reflex_id, reflex_id_full, mode, selector, operation_counter, connection_id, connection_id_full, timestamp
|
15
|
-
# Available colors: green, yellow, blue, magenta, cyan, white
|
15
|
+
# Available colors: red, green, yellow, blue, magenta, cyan, white
|
16
16
|
# You can also use attributes from your ActionCable Connection's identifiers that resolve to valid ActiveRecord models
|
17
17
|
# eg. if your connection is `identified_by :current_user` and your User model has an email attribute, you can access r.email (it will display `-` if the user isn't logged in)
|
18
|
+
# Learn more at: https://docs.stimulusreflex.com/troubleshooting#stimulusreflex-logging
|
18
19
|
|
19
20
|
# config.logging = proc { "[#{session_id}] #{operation_counter.magenta} #{reflex_info.green} -> #{selector.cyan} via #{mode} Morph (#{operation.yellow})" }
|
21
|
+
|
22
|
+
# Optimized for speed, StimulusReflex doesn't enable Rack middleware by default.
|
23
|
+
# If you are using Page Morphs and your app uses Rack middleware to rewrite part of the request path, you must enable those middleware modules in StimulusReflex.
|
24
|
+
#
|
25
|
+
# Learn more about registering Rack middleware in Rails here: https://guides.rubyonrails.org/rails_on_rack.html#configuring-middleware-stack
|
26
|
+
|
27
|
+
# config.middleware.use FirstRackMiddleware
|
28
|
+
# config.middleware.use SecondRackMiddleware
|
20
29
|
end
|
data/lib/stimulus_reflex.rb
CHANGED
@@ -11,6 +11,7 @@ require "cable_ready"
|
|
11
11
|
require "stimulus_reflex/version"
|
12
12
|
require "stimulus_reflex/cable_ready_channels"
|
13
13
|
require "stimulus_reflex/configuration"
|
14
|
+
require "stimulus_reflex/callbacks"
|
14
15
|
require "stimulus_reflex/reflex"
|
15
16
|
require "stimulus_reflex/element"
|
16
17
|
require "stimulus_reflex/sanity_checker"
|
@@ -24,7 +25,7 @@ require "stimulus_reflex/logger"
|
|
24
25
|
module StimulusReflex
|
25
26
|
class Engine < Rails::Engine
|
26
27
|
initializer "stimulus_reflex.sanity_check" do
|
27
|
-
SanityChecker.check!
|
28
|
+
SanityChecker.check! unless Rails.env.production?
|
28
29
|
end
|
29
30
|
end
|
30
31
|
end
|
@@ -1,18 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module StimulusReflex
|
2
4
|
class CableReadyChannels
|
5
|
+
delegate :[], to: "cable_ready_channels"
|
6
|
+
|
3
7
|
def initialize(stream_name)
|
4
|
-
@
|
5
|
-
|
8
|
+
@stream_name = stream_name
|
9
|
+
end
|
10
|
+
|
11
|
+
def cable_ready_channels
|
12
|
+
CableReady::Channels.instance
|
13
|
+
end
|
14
|
+
|
15
|
+
def stimulus_reflex_channel
|
16
|
+
CableReady::Channels.instance[@stream_name]
|
6
17
|
end
|
7
18
|
|
8
19
|
def method_missing(name, *args)
|
9
|
-
return
|
10
|
-
|
20
|
+
return stimulus_reflex_channel.public_send(name, *args) if stimulus_reflex_channel.respond_to?(name)
|
21
|
+
super
|
11
22
|
end
|
12
23
|
|
13
24
|
def respond_to_missing?(name, include_all)
|
14
|
-
|
15
|
-
@cable_ready_channels.respond_to?(name, include_all)
|
25
|
+
stimulus_reflex_channel.respond_to?(name) || super
|
16
26
|
end
|
17
27
|
end
|
18
28
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require "active_support/concern"
|
2
|
+
|
3
|
+
module StimulusReflex
|
4
|
+
module Callbacks
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
include ActiveSupport::Callbacks
|
9
|
+
define_callbacks :process, skip_after_callbacks_if_terminated: true
|
10
|
+
end
|
11
|
+
|
12
|
+
class_methods do
|
13
|
+
def before_reflex(*args, &block)
|
14
|
+
add_callback(:before, *args, &block)
|
15
|
+
end
|
16
|
+
|
17
|
+
def after_reflex(*args, &block)
|
18
|
+
add_callback(:after, *args, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def around_reflex(*args, &block)
|
22
|
+
add_callback(:around, *args, &block)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def add_callback(kind, *args, &block)
|
28
|
+
options = args.extract_options!
|
29
|
+
options.assert_valid_keys :if, :unless, :only, :except
|
30
|
+
set_callback(*[:process, kind, args, normalize_callback_options!(options)].flatten, &block)
|
31
|
+
end
|
32
|
+
|
33
|
+
def normalize_callback_options!(options)
|
34
|
+
normalize_callback_option! options, :only, :if
|
35
|
+
normalize_callback_option! options, :except, :unless
|
36
|
+
options
|
37
|
+
end
|
38
|
+
|
39
|
+
def normalize_callback_option!(options, from, to)
|
40
|
+
if (from = options.delete(from))
|
41
|
+
from_set = Array(from).map(&:to_s).to_set
|
42
|
+
from = proc { |reflex| from_set.include? reflex.method_name }
|
43
|
+
options[to] = Array(options[to]).unshift(from)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -14,7 +14,7 @@ module StimulusReflex
|
|
14
14
|
end
|
15
15
|
|
16
16
|
class Configuration
|
17
|
-
attr_accessor :on_failed_sanity_checks, :parent_channel, :logging
|
17
|
+
attr_accessor :on_failed_sanity_checks, :parent_channel, :logging, :middleware
|
18
18
|
|
19
19
|
DEFAULT_LOGGING = proc { "[#{session_id}] #{operation_counter.magenta} #{reflex_info.green} -> #{selector.cyan} via #{mode} Morph (#{operation.yellow})" }
|
20
20
|
|
@@ -22,6 +22,7 @@ module StimulusReflex
|
|
22
22
|
@on_failed_sanity_checks = :exit
|
23
23
|
@parent_channel = "ApplicationCable::Channel"
|
24
24
|
@logging = DEFAULT_LOGGING
|
25
|
+
@middleware = ActionDispatch::MiddlewareStack.new
|
25
26
|
end
|
26
27
|
end
|
27
28
|
end
|
@@ -79,22 +79,22 @@ module StimulusReflex
|
|
79
79
|
Time.now.strftime("%Y-%m-%d %H:%M:%S")
|
80
80
|
end
|
81
81
|
|
82
|
-
def method_missing
|
83
|
-
return send(
|
82
|
+
def method_missing(name, *args)
|
83
|
+
return send(name) if private_instance_methods.include?(name.to_sym)
|
84
84
|
|
85
85
|
reflex.connection.identifiers.each do |identifier|
|
86
86
|
ident = reflex.connection.send(identifier)
|
87
|
-
return ident.send(
|
87
|
+
return ident.send(name) if ident.respond_to?(:attributes) && ident.attributes.key?(name.to_s)
|
88
88
|
end
|
89
89
|
"-"
|
90
90
|
end
|
91
91
|
|
92
|
-
def respond_to_missing?
|
93
|
-
return true if private_instance_methods.include?(
|
92
|
+
def respond_to_missing?(name, include_all)
|
93
|
+
return true if private_instance_methods.include?(name.to_sym)
|
94
94
|
|
95
95
|
reflex.connection.identifiers.each do |identifier|
|
96
96
|
ident = reflex.connection.send(identifier)
|
97
|
-
return true if ident.respond_to?(:attributes) && ident.attributes.key?(
|
97
|
+
return true if ident.respond_to?(:attributes) && ident.attributes.key?(name.to_s)
|
98
98
|
end
|
99
99
|
false
|
100
100
|
end
|
@@ -1,59 +1,33 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
ClientAttributes = Struct.new(:reflex_id, :reflex_controller, :
|
3
|
+
ClientAttributes = Struct.new(:reflex_id, :reflex_controller, :xpath_controller, :xpath_element, :permanent_attribute_name, keyword_init: true)
|
4
4
|
|
5
5
|
class StimulusReflex::Reflex
|
6
6
|
include ActiveSupport::Rescuable
|
7
|
-
include
|
8
|
-
|
9
|
-
define_callbacks :process, skip_after_callbacks_if_terminated: true
|
10
|
-
|
11
|
-
class << self
|
12
|
-
def before_reflex(*args, &block)
|
13
|
-
add_callback(:before, *args, &block)
|
14
|
-
end
|
15
|
-
|
16
|
-
def after_reflex(*args, &block)
|
17
|
-
add_callback(:after, *args, &block)
|
18
|
-
end
|
19
|
-
|
20
|
-
def around_reflex(*args, &block)
|
21
|
-
add_callback(:around, *args, &block)
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
def add_callback(kind, *args, &block)
|
27
|
-
options = args.extract_options!
|
28
|
-
options.assert_valid_keys :if, :unless, :only, :except
|
29
|
-
set_callback(*[:process, kind, args, normalize_callback_options!(options)].flatten, &block)
|
30
|
-
end
|
31
|
-
|
32
|
-
def normalize_callback_options!(options)
|
33
|
-
normalize_callback_option! options, :only, :if
|
34
|
-
normalize_callback_option! options, :except, :unless
|
35
|
-
options
|
36
|
-
end
|
37
|
-
|
38
|
-
def normalize_callback_option!(options, from, to)
|
39
|
-
if (from = options.delete(from))
|
40
|
-
from_set = Array(from).map(&:to_s).to_set
|
41
|
-
from = proc { |reflex| from_set.include? reflex.method_name }
|
42
|
-
options[to] = Array(options[to]).unshift(from)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
7
|
+
include StimulusReflex::Callbacks
|
46
8
|
|
47
9
|
attr_reader :cable_ready, :channel, :url, :element, :selectors, :method_name, :broadcaster, :client_attributes, :logger
|
48
10
|
|
49
11
|
alias_method :action_name, :method_name # for compatibility with controller libraries like Pundit that expect an action name
|
50
12
|
|
51
13
|
delegate :connection, :stream_name, to: :channel
|
52
|
-
delegate :flash, :session, to: :request
|
14
|
+
delegate :controller_class, :flash, :session, to: :request
|
53
15
|
delegate :broadcast, :broadcast_message, to: :broadcaster
|
54
|
-
delegate :reflex_id, :reflex_controller, :
|
16
|
+
delegate :reflex_id, :reflex_controller, :xpath_controller, :xpath_element, :permanent_attribute_name, to: :client_attributes
|
17
|
+
delegate :render, to: :controller_class
|
55
18
|
|
56
19
|
def initialize(channel, url: nil, element: nil, selectors: [], method_name: nil, params: {}, client_attributes: {})
|
20
|
+
if is_a? CableReady::Broadcaster
|
21
|
+
message = <<~MSG
|
22
|
+
|
23
|
+
#{self.class.name} includes CableReady::Broadcaster, and you need to remove it.
|
24
|
+
Reflexes have their own CableReady interface. You can just assume that it's present.
|
25
|
+
See https://docs.stimulusreflex.com/rtfm/cableready#using-cableready-inside-a-reflex-action for more details.
|
26
|
+
|
27
|
+
MSG
|
28
|
+
raise TypeError.new(message.strip)
|
29
|
+
end
|
30
|
+
|
57
31
|
@channel = channel
|
58
32
|
@url = url
|
59
33
|
@element = element
|
@@ -86,6 +60,14 @@ class StimulusReflex::Reflex
|
|
86
60
|
)
|
87
61
|
|
88
62
|
env = connection.env.merge(mock_env)
|
63
|
+
|
64
|
+
middleware = StimulusReflex.config.middleware
|
65
|
+
|
66
|
+
if middleware.any?
|
67
|
+
stack = middleware.build(Rails.application.routes)
|
68
|
+
stack.call(env)
|
69
|
+
end
|
70
|
+
|
89
71
|
req = ActionDispatch::Request.new(env)
|
90
72
|
|
91
73
|
path_params = Rails.application.routes.recognize_path_with_request(req, url, req.env[:extras] || {})
|
@@ -114,11 +96,11 @@ class StimulusReflex::Reflex
|
|
114
96
|
|
115
97
|
def controller
|
116
98
|
@controller ||= begin
|
117
|
-
|
99
|
+
controller_class.new.tap do |c|
|
118
100
|
c.instance_variable_set :"@stimulus_reflex", true
|
119
101
|
instance_variables.each { |name| c.instance_variable_set name, instance_variable_get(name) }
|
120
|
-
c.
|
121
|
-
c.
|
102
|
+
c.set_request! request
|
103
|
+
c.set_response! controller_class.make_response!(request)
|
122
104
|
end
|
123
105
|
end
|
124
106
|
end
|
@@ -146,4 +128,8 @@ class StimulusReflex::Reflex
|
|
146
128
|
def params
|
147
129
|
@_params ||= ActionController::Parameters.new(request.parameters)
|
148
130
|
end
|
131
|
+
|
132
|
+
def dom_id(record_or_class, prefix = nil)
|
133
|
+
"#" + ActionView::RecordIdentifier.dom_id(record_or_class, prefix).to_s
|
134
|
+
end
|
149
135
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class StimulusReflex::SanityChecker
|
4
|
+
NODE_VERSION_FORMAT = /(\d+\.\d+\.\d+.*):/
|
4
5
|
JSON_VERSION_FORMAT = /(\d+\.\d+\.\d+.*)"/
|
5
6
|
|
6
7
|
class << self
|
@@ -86,6 +87,8 @@ class StimulusReflex::SanityChecker
|
|
86
87
|
def find_javascript_package_version
|
87
88
|
if (match = search_file(package_json_path, regex: /version/))
|
88
89
|
match[JSON_VERSION_FORMAT, 1]
|
90
|
+
elsif (match = search_file(yarn_lock_path, regex: /^stimulus_reflex/))
|
91
|
+
match[NODE_VERSION_FORMAT, 1]
|
89
92
|
end
|
90
93
|
end
|
91
94
|
|
@@ -98,6 +101,10 @@ class StimulusReflex::SanityChecker
|
|
98
101
|
Rails.root.join("node_modules", "stimulus_reflex", "package.json")
|
99
102
|
end
|
100
103
|
|
104
|
+
def yarn_lock_path
|
105
|
+
Rails.root.join("yarn.lock")
|
106
|
+
end
|
107
|
+
|
101
108
|
def initializer_path
|
102
109
|
@_initializer_path ||= Rails.root.join("config", "initializers", "stimulus_reflex.rb")
|
103
110
|
end
|
@@ -6,9 +6,10 @@ require "stimulus_reflex/version"
|
|
6
6
|
namespace :stimulus_reflex do
|
7
7
|
desc "Install StimulusReflex in this application"
|
8
8
|
task install: :environment do
|
9
|
-
system "
|
9
|
+
system "rails dev:cache" unless Rails.root.join("tmp", "caching-dev.txt").exist?
|
10
10
|
gem_version = StimulusReflex::VERSION.gsub(".pre", "-pre")
|
11
11
|
system "yarn add stimulus_reflex@#{gem_version}"
|
12
|
+
system "bundle exec rails webpacker:install:stimulus"
|
12
13
|
main_folder = defined?(Webpacker) ? Webpacker.config.source_path.to_s.gsub("#{Rails.root}/", "") : "app/javascript"
|
13
14
|
|
14
15
|
FileUtils.mkdir_p Rails.root.join("#{main_folder}/controllers"), verbose: true
|
@@ -39,7 +40,7 @@ namespace :stimulus_reflex do
|
|
39
40
|
|
40
41
|
unless lines.find { |line| line.start_with?("import controller") }
|
41
42
|
matches = lines.select { |line| line =~ /\A(require|import)/ }
|
42
|
-
lines.insert lines.index(matches.last).to_i + 1, "import controller from '
|
43
|
+
lines.insert lines.index(matches.last).to_i + 1, "import controller from '../controllers/application_controller'\n"
|
43
44
|
end
|
44
45
|
|
45
46
|
initialize_line = lines.find { |line| line.start_with?("StimulusReflex.initialize") }
|
@@ -67,6 +68,10 @@ namespace :stimulus_reflex do
|
|
67
68
|
system "bundle exec rails generate stimulus_reflex example"
|
68
69
|
puts "Generating default StimulusReflex configuration file into your application config/initializers directory"
|
69
70
|
system "bundle exec rails generate stimulus_reflex:config"
|
70
|
-
|
71
|
+
|
72
|
+
puts
|
73
|
+
puts "StimulusReflex and CableReady have been successfully installed!"
|
74
|
+
puts "Go to https://docs.stimulusreflex.com/quickstart if you need help getting started."
|
75
|
+
puts
|
71
76
|
end
|
72
77
|
end
|
data/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "stimulus_reflex",
|
3
|
-
"version": "3.4.0
|
3
|
+
"version": "3.4.0",
|
4
4
|
"description": "Build reactive applications with the Rails tooling you already know and love.",
|
5
5
|
"keywords": [
|
6
6
|
"ruby",
|
@@ -41,7 +41,7 @@
|
|
41
41
|
},
|
42
42
|
"dependencies": {
|
43
43
|
"@rails/actioncable": ">= 6.0",
|
44
|
-
"cable_ready": ">= 4.
|
44
|
+
"cable_ready": ">= 4.5.0"
|
45
45
|
},
|
46
46
|
"devDependencies": {
|
47
47
|
"@babel/core": "^7.6.2",
|
@@ -52,6 +52,6 @@
|
|
52
52
|
"jsdom": "^16.0.1",
|
53
53
|
"mocha": "^8.0.1",
|
54
54
|
"prettier-standard": "^16.1.0",
|
55
|
-
"stimulus": "
|
55
|
+
"stimulus": ">= 1.1"
|
56
56
|
}
|
57
57
|
}
|
data/stimulus_reflex.gemspec
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require File.expand_path("../lib/stimulus_reflex/version", __FILE__)
|
2
4
|
|
3
5
|
Gem::Specification.new do |gem|
|
@@ -30,7 +32,7 @@ Gem::Specification.new do |gem|
|
|
30
32
|
gem.add_dependency "nokogiri"
|
31
33
|
gem.add_dependency "rails", ">= 5.2"
|
32
34
|
gem.add_dependency "redis"
|
33
|
-
gem.add_dependency "cable_ready", ">= 4.
|
35
|
+
gem.add_dependency "cable_ready", ">= 4.5"
|
34
36
|
|
35
37
|
gem.add_development_dependency "bundler", "~> 2.0"
|
36
38
|
gem.add_development_dependency "pry-nav"
|