view_component_reducible 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5505b895dc07055d3d09ad5e466316aadab92321fd2b8a71c3889cc1284059f2
4
- data.tar.gz: 66757165853350bb660d16605c935ec5072eb01aedf4dfaf62419ab4d1af5439
3
+ metadata.gz: 6b8576a2267bf71dae86a6339162039c3b2effa03bbd25f0eefb1fa378481244
4
+ data.tar.gz: eb2629af05937f40b4c87731f062f32d2640bb7a78cc0ceff20a4d6d4188c4f3
5
5
  SHA512:
6
- metadata.gz: a5a98ecba5e6ac762086bce05b77409360708c91489d6bbd23bba626e9cc0f6ed1f06ee138b90bcb44c68c06e4b35f4474365ea4b5baae3600283e261e1b09aa
7
- data.tar.gz: b56697564e122c374d7291cd1955678af2fb79ca307351b74f4c39043e7912bebab33d4f2ae17d26644a46a42a6f9781267be0db27601b5bbad14affe7fa9a3d
6
+ metadata.gz: 554e95d73a13b21d4bf47185b669d63cfec7a5846668de2889b9766efb30d80e872f2739ac33e0c70af99f4673aaf74bc17cf06725c9ea68ea9dfee53d637312
7
+ data.tar.gz: a507b13dae0abeefa7961ac0dddf5679d22bc90e64eb6a6324481b615aa6ee68e1e81e2b6c1c3ea5383c50175940898e91b7f57fb91d2c8736d23cd20908f4f1
@@ -4,8 +4,14 @@ module ViewComponentReducible
4
4
  module Adapter
5
5
  # Base adapter interface for envelope serialization.
6
6
  class Base
7
+ # @return [String]
8
+ def self.state_param_name
9
+ 'vcr_state'
10
+ end
11
+
7
12
  # @param secret [String]
8
- def initialize(secret:)
13
+ # @param _kwargs [Hash]
14
+ def initialize(secret:, **_kwargs)
9
15
  @secret = secret
10
16
  end
11
17
 
@@ -23,7 +23,7 @@ module ViewComponentReducible
23
23
  # @param request [ActionDispatch::Request]
24
24
  # @return [Hash]
25
25
  def load(request:)
26
- signed = request.params.fetch('vcr_state')
26
+ signed = request.params.fetch(self.class.state_param_name)
27
27
  verifier.verify(signed)
28
28
  end
29
29
  end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support'
4
+ require 'active_support/message_verifier'
5
+ require 'securerandom'
6
+ require 'json'
7
+
8
+ module ViewComponentReducible
9
+ module Adapter
10
+ # Redis adapter storing envelope outside of the session.
11
+ class Redis < Base
12
+ DEFAULT_TTL = 900
13
+ DEFAULT_NAMESPACE = 'vcr'
14
+
15
+ def self.state_param_name
16
+ 'vcr_state_key'
17
+ end
18
+
19
+ # @param secret [String]
20
+ # @param redis [Object, nil]
21
+ # @param redis_url [String, nil]
22
+ # @param redis_ttl [Integer, nil]
23
+ # @param redis_namespace [String, nil]
24
+ def initialize(secret:, redis: nil, redis_url: nil, redis_ttl: DEFAULT_TTL, redis_namespace: DEFAULT_NAMESPACE)
25
+ super(secret:)
26
+ @redis = redis || build_client(redis_url)
27
+ @redis_ttl = redis_ttl
28
+ @redis_namespace = redis_namespace
29
+ end
30
+
31
+ # @return [ActiveSupport::MessageVerifier]
32
+ def verifier
33
+ @verifier ||= ActiveSupport::MessageVerifier.new(@secret, digest: 'SHA256', serializer: JSON)
34
+ end
35
+
36
+ # @param envelope [Hash]
37
+ # @param request [ActionDispatch::Request]
38
+ # @return [String]
39
+ def dump(envelope, request:)
40
+ _ = request
41
+ key = SecureRandom.hex(16)
42
+ write(key, JSON.generate(envelope))
43
+ verifier.generate({ 'k' => key })
44
+ end
45
+
46
+ # @param request [ActionDispatch::Request]
47
+ # @return [Hash]
48
+ def load(request:)
49
+ signed = request.params.fetch(self.class.state_param_name)
50
+ payload = verifier.verify(signed)
51
+ key = payload.fetch('k')
52
+ raw = @redis.get(redis_key(key))
53
+ raise KeyError, "Missing envelope for #{key}" if raw.nil?
54
+
55
+ JSON.parse(raw)
56
+ end
57
+
58
+ private
59
+
60
+ def build_client(redis_url)
61
+ require 'redis'
62
+ return ::Redis.new if redis_url.nil? || redis_url == ''
63
+
64
+ ::Redis.new(url: redis_url)
65
+ rescue LoadError
66
+ raise LoadError, 'Redis adapter requires the redis gem. Add `gem "redis"` to your bundle.'
67
+ end
68
+
69
+ def write(key, payload)
70
+ if @redis_ttl
71
+ @redis.setex(redis_key(key), @redis_ttl, payload)
72
+ else
73
+ @redis.set(redis_key(key), payload)
74
+ end
75
+ end
76
+
77
+ def redis_key(key)
78
+ "#{@redis_namespace}:#{key}"
79
+ end
80
+ end
81
+ end
82
+ end
@@ -8,6 +8,10 @@ module ViewComponentReducible
8
8
  module Adapter
9
9
  # Session adapter storing envelope in server session.
10
10
  class Session < Base
11
+ def self.state_param_name
12
+ 'vcr_state_key'
13
+ end
14
+
11
15
  # @return [ActiveSupport::MessageVerifier]
12
16
  def verifier
13
17
  @verifier ||= ActiveSupport::MessageVerifier.new(@secret, digest: 'SHA256', serializer: JSON)
@@ -18,14 +22,17 @@ module ViewComponentReducible
18
22
  # @return [String]
19
23
  def dump(envelope, request:)
20
24
  key = SecureRandom.hex(16)
21
- request.session["vcr:#{key}"] = envelope
25
+ session = request.session
26
+ session_keys = session.respond_to?(:keys) ? session.keys : session.to_hash.keys
27
+ session_keys.grep(/\Avcr:/).each { |session_key| session.delete(session_key) }
28
+ session["vcr:#{key}"] = envelope
22
29
  verifier.generate({ 'k' => key })
23
30
  end
24
31
 
25
32
  # @param request [ActionDispatch::Request]
26
33
  # @return [Hash]
27
34
  def load(request:)
28
- signed = request.params.fetch('vcr_state')
35
+ signed = request.params.fetch(self.class.state_param_name)
29
36
  payload = verifier.verify(signed)
30
37
  key = payload.fetch('k')
31
38
  request.session.fetch("vcr:#{key}")
@@ -4,11 +4,15 @@ module ViewComponentReducible
4
4
  # Global configuration for adapter and secrets.
5
5
  class Configuration
6
6
  # @return [Class]
7
- attr_accessor :adapter, :secret
7
+ attr_accessor :adapter, :secret, :redis, :redis_url, :redis_ttl, :redis_namespace
8
8
 
9
9
  def initialize
10
10
  @adapter = Adapter::Session
11
11
  @secret = nil
12
+ @redis = nil
13
+ @redis_url = nil
14
+ @redis_ttl = nil
15
+ @redis_namespace = nil
12
16
  end
13
17
 
14
18
  # Build adapter instance for a controller request.
@@ -19,7 +23,13 @@ module ViewComponentReducible
19
23
  resolved_secret = secret || default_secret
20
24
  raise 'ViewComponentReducible secret is missing' if resolved_secret.nil?
21
25
 
22
- (adapter_class || adapter).new(secret: resolved_secret)
26
+ kwargs = { secret: resolved_secret }
27
+ kwargs[:redis] = redis if redis
28
+ kwargs[:redis_url] = redis_url if redis_url
29
+ kwargs[:redis_ttl] = redis_ttl unless redis_ttl.nil?
30
+ kwargs[:redis_namespace] = redis_namespace if redis_namespace
31
+
32
+ (adapter_class || adapter).new(**kwargs)
23
33
  end
24
34
 
25
35
  private
@@ -24,10 +24,11 @@ module ViewComponentReducible
24
24
  def vcr_dispatch_form(state:, msg_type:, msg_payload: {}, target_path: nil, url: '/vcr/dispatch', &block)
25
25
  payload = msg_payload.is_a?(String) ? msg_payload : JSON.generate(msg_payload)
26
26
  resolved_target = target_path || vcr_envelope_path || instance_variable_get(:@vcr_current_path) || 'root'
27
+ state_param = ViewComponentReducible.config.adapter.state_param_name
27
28
 
28
- form_tag(url, method: :post, data: { vcr_form: true }) do
29
+ form_tag(url, method: :post, data: { vcr_form: true, vcr_state_param: state_param }) do
29
30
  body = [
30
- hidden_field_tag('vcr_state', state),
31
+ hidden_field_tag(state_param, state),
31
32
  hidden_field_tag('vcr_msg_type', msg_type),
32
33
  hidden_field_tag('vcr_msg_payload', payload),
33
34
  hidden_field_tag('vcr_target_path', resolved_target),
@@ -74,7 +75,8 @@ module ViewComponentReducible
74
75
  if (payload.state) {
75
76
  var boundary = document.querySelector('[data-vcr-path="' + targetPath + '"]');
76
77
  if (boundary) {
77
- boundary.querySelectorAll('input[name="vcr_state"]').forEach(function(input) {
78
+ var stateParam = form.dataset.vcrStateParam || "vcr_state";
79
+ boundary.querySelectorAll('input[name="' + stateParam + '"]').forEach(function(input) {
78
80
  input.value = payload.state;
79
81
  });
80
82
  }
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ViewComponentReducible
4
- VERSION = '0.1.3'
4
+ VERSION = '0.1.4'
5
5
  end
@@ -6,6 +6,7 @@ require_relative 'view_component_reducible/msg'
6
6
  require_relative 'view_component_reducible/adapter/base'
7
7
  require_relative 'view_component_reducible/adapter/hidden_field'
8
8
  require_relative 'view_component_reducible/adapter/session'
9
+ require_relative 'view_component_reducible/adapter/redis'
9
10
  require_relative 'view_component_reducible/helpers'
10
11
  require_relative 'view_component_reducible/state/schema'
11
12
  require_relative 'view_component_reducible/state/dsl'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: view_component_reducible
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - manabeai
@@ -65,6 +65,20 @@ dependencies:
65
65
  - - ">="
66
66
  - !ruby/object:Gem::Version
67
67
  version: '6.1'
68
+ - !ruby/object:Gem::Dependency
69
+ name: redis
70
+ requirement: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '4.0'
75
+ type: :runtime
76
+ prerelease: false
77
+ version_requirements: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '4.0'
68
82
  - !ruby/object:Gem::Dependency
69
83
  name: view_component
70
84
  requirement: !ruby/object:Gem::Requirement
@@ -94,6 +108,7 @@ files:
94
108
  - lib/view_component_reducible.rb
95
109
  - lib/view_component_reducible/adapter/base.rb
96
110
  - lib/view_component_reducible/adapter/hidden_field.rb
111
+ - lib/view_component_reducible/adapter/redis.rb
97
112
  - lib/view_component_reducible/adapter/session.rb
98
113
  - lib/view_component_reducible/component.rb
99
114
  - lib/view_component_reducible/configuration.rb