view_component_reflex 1.6.1 → 1.7.0

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: 2269d8639ced76028ffe2a5970960d7381c862a75ce36481a84d8cf8886acd6c
4
- data.tar.gz: c368a487c3a2d97b4207ecb47558877596f9f9dccc7aa63f363598bc72a4eb82
3
+ metadata.gz: eb949fc8de60d18d54d72195cd04947ba24ef73db4091b2ddd0c2992287df7d0
4
+ data.tar.gz: c474384a6b9c073ba4efbf924067113971e67c4e8bdc0fbfa6462471ecf95b6e
5
5
  SHA512:
6
- metadata.gz: 4822e9370947d8881b8f33ca8a00df19a9458ca31f9da4bc84bcfb438e768f37226a2790f489efe94ec36418f77ed4d32a122a003653ec3120ddc49df5af2a1d
7
- data.tar.gz: 0f38085c800aa78f43e6df67cec9664115fed2cbce0cefc7fb89dbe2a0b3f624d7adfff1a71e542039af40a6b247744677e96a0115afe6f5f5ad65fb4c2a78df
6
+ metadata.gz: e0f4a365d380e55ba8deb5f567f35fa81b2aa8ab108cd2aca4f6e97041139e8e53f446f30db3ddcea0ee0fcb08e62b2f98feef14b83f5810c54ce705a6564716
7
+ data.tar.gz: df46044a3c7bddc9ab204ddb052fce04f0cecf190428043a3aa4ff2fb5a1b86d7d4e9524fa509ecbea51991641f8b4da9b8eaed2b1f4ede565c6cdb922a07724
data/README.md CHANGED
@@ -70,8 +70,8 @@ end
70
70
  ```
71
71
 
72
72
  ### omitted_from_state
73
- Return an array of instance variables you want to omit from state. Useful if you have an object
74
- that isn't serializable as an instance variable, like a form.
73
+ Return an array of instance variables you want to omit from state. Only really useful if you're using the session state
74
+ adapter, and you have an instance variable that can't be serialized.
75
75
 
76
76
  ```ruby
77
77
  def omitted_from_state
@@ -181,6 +181,11 @@ end
181
181
  <% end
182
182
  ```
183
183
 
184
+ ## State
185
+
186
+ By default, view_component_reflex stores component state in memory. You can optionally set the state adapter
187
+ to use the session by changing `config.state_adapter` to `ViewComponentReflex::StateAdapter::Session`
188
+
184
189
  ## Custom State Adapters
185
190
 
186
191
  ViewComponentReflex uses session for its state by default. To change this, add
@@ -4,21 +4,53 @@ module ViewComponentReflex
4
4
  def init_stimulus_reflex
5
5
  klass = self
6
6
  @stimulus_reflex ||= Object.const_set(name + "Reflex", Class.new(StimulusReflex::Reflex) {
7
- def refresh!(primary_selector = "[data-controller~=\"#{stimulus_controller}\"][data-key=\"#{element.dataset[:key]}\"]", *selectors)
7
+ def refresh!(*selectors)
8
8
  save_state
9
- @channel.send :render_page_and_broadcast_morph, self, [primary_selector, *selectors], {
10
- "dataset" => element.dataset.to_h,
11
- "args" => [],
12
- "attrs" => element.attributes.to_h,
13
- "selectors" => ["body"],
14
- "target" => "#{self.class.name}##{method_name}",
15
- "url" => request.url,
16
- "permanent_attribute_name" => "data-reflex-permanent"
17
- }
9
+
10
+ # If the component has instance variables omitted from state,
11
+ # we can't render it to string from here because those instance
12
+ # variables will be missing. In that case, set the selectors to the
13
+ # default selector and manually morph the page
14
+ if selectors.empty? && !component.can_render_to_string?
15
+ selectors.push selector
16
+ end
17
+
18
+ # If we're just updating the component itself, we can
19
+ # directly render it instead of rendering the entire page again
20
+ if selectors.empty?
21
+ refresh_component!
22
+ else
23
+ @channel.send :render_page_and_broadcast_morph, self, selectors, {
24
+ "dataset" => element.dataset.to_h,
25
+ "args" => [],
26
+ "attrs" => element.attributes.to_h,
27
+ "selectors" => ["body"],
28
+ "target" => "#{self.class.name}##{method_name}",
29
+ "url" => request.url,
30
+ "permanent_attribute_name" => permanent_attribute_name
31
+ }
32
+ end
33
+ end
34
+
35
+ def refresh_component!
36
+ # The component can't figure out the key when we render from here
37
+ # Luckily we already know the key, so we can manually override it
38
+ component.tap do |k|
39
+ k.define_singleton_method(:key) do
40
+ element.dataset[:key]
41
+ end
42
+ end
43
+ html = controller.render_component_to_string(component)
44
+ document = Nokogiri::HTML(html)
45
+ morph selector, document.css("#{selector} > *").to_s
46
+ end
47
+
48
+ def selector
49
+ "[data-controller~=\"#{stimulus_controller}\"][data-key=\"#{element.dataset[:key]}\"]"
18
50
  end
19
51
 
20
52
  def refresh_all!
21
- refresh!("body")
53
+ morph :body, render_page(self)
22
54
  end
23
55
 
24
56
  # SR's delegate_call_to_reflex in channel.rb
@@ -32,11 +64,6 @@ module ViewComponentReflex
32
64
  !!name.to_proc
33
65
  end
34
66
 
35
- before_reflex do |a|
36
- a.send a.method_name
37
- throw :abort
38
- end
39
-
40
67
  def method_missing(name, *args)
41
68
  super unless respond_to_missing?(name)
42
69
  state.each do |k, v|
@@ -85,7 +112,7 @@ module ViewComponentReflex
85
112
 
86
113
  def save_state
87
114
  new_state = {}
88
- component.instance_variables.each do |k|
115
+ component.safe_instance_variables.each do |k|
89
116
  new_state[k] = component.instance_variable_get(k)
90
117
  end
91
118
  set_state(new_state)
@@ -102,6 +129,10 @@ module ViewComponentReflex
102
129
  helpers.controller.instance_variable_get(:@stimulus_reflex)
103
130
  end
104
131
 
132
+ def can_render_to_string?
133
+ omitted_from_state.empty?
134
+ end
135
+
105
136
  def component_controller(opts_or_tag = :div, opts = {}, &blk)
106
137
  self.class.init_stimulus_reflex
107
138
  init_key
@@ -165,18 +196,10 @@ module ViewComponentReflex
165
196
 
166
197
  def key
167
198
  # initialize session state
168
- if !stimulus_reflex? || session[@key].nil?
169
- new_state = {}
170
-
171
- # this will almost certainly break
172
- blacklist = [
173
- :@view_context, :@lookup_context, :@view_renderer, :@view_flow,
174
- :@virtual_path, :@variant, :@current_template, :@output_buffer, :@key,
175
- :@helpers, :@controller, :@request, :@content
176
- ]
177
- instance_variables.reject { |k| blacklist.include?(k) }.each do |k|
178
- new_state[k] = instance_variable_get(k) unless omitted_from_state.include?(k)
179
- end
199
+ if !stimulus_reflex? || ViewComponentReflex::Engine.state_adapter.state(request, @key).empty?
200
+
201
+ new_state = create_safe_state
202
+
180
203
  ViewComponentReflex::Engine.state_adapter.store_state(request, @key, new_state)
181
204
  ViewComponentReflex::Engine.state_adapter.store_state(request, "#{@key}_initial", new_state)
182
205
  else
@@ -190,8 +213,30 @@ module ViewComponentReflex
190
213
  @key
191
214
  end
192
215
 
216
+ def safe_instance_variables
217
+ instance_variables - unsafe_instance_variables
218
+ end
219
+
193
220
  private
194
221
 
222
+ def unsafe_instance_variables
223
+ [
224
+ :@view_context, :@lookup_context, :@view_renderer, :@view_flow,
225
+ :@virtual_path, :@variant, :@current_template, :@output_buffer, :@key,
226
+ :@helpers, :@controller, :@request, :@content, :@tag_builder
227
+ ]
228
+ end
229
+
230
+ def create_safe_state
231
+ new_state = {}
232
+
233
+ # this will almost certainly break
234
+ safe_instance_variables.each do |k|
235
+ new_state[k] = instance_variable_get(k) unless omitted_from_state.include?(k)
236
+ end
237
+ new_state
238
+ end
239
+
195
240
  def merge_data_attributes(options, attributes)
196
241
  data = options[:data]
197
242
  if data.nil?
@@ -1,7 +1,8 @@
1
- require "view_component_reflex/state_adapter/session"
2
- require "view_component_reflex/engine"
3
- require 'stimulus_reflex'
4
-
5
- module ViewComponentReflex
6
- # Your code goes here...
7
- end
1
+ require "view_component_reflex/state_adapter/session"
2
+ require "view_component_reflex/state_adapter/memory"
3
+ require "view_component_reflex/engine"
4
+ require 'stimulus_reflex'
5
+
6
+ module ViewComponentReflex
7
+ # Your code goes here...
8
+ end
@@ -1,13 +1,13 @@
1
- module ViewComponentReflex
2
- class Engine < ::Rails::Engine
3
- class << self
4
- mattr_accessor :state_adapter
5
-
6
- self.state_adapter = StateAdapter::Session
7
- end
8
-
9
- def self.configure
10
- yield self if block_given?
11
- end
12
- end
13
- end
1
+ module ViewComponentReflex
2
+ class Engine < ::Rails::Engine
3
+ class << self
4
+ mattr_accessor :state_adapter
5
+
6
+ self.state_adapter = StateAdapter::Memory
7
+ end
8
+
9
+ def self.configure
10
+ yield self if block_given?
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,25 @@
1
+ VIEW_COMPONENT_REFLEX_MEMORY_STATE = {}
2
+ module ViewComponentReflex
3
+ module StateAdapter
4
+ class Memory
5
+ def self.state(request, key)
6
+ VIEW_COMPONENT_REFLEX_MEMORY_STATE[request.session.id.to_s] ||= {}
7
+ VIEW_COMPONENT_REFLEX_MEMORY_STATE[request.session.id.to_s][key] ||= {}
8
+ end
9
+
10
+ def self.set_state(request, _, key, new_state)
11
+ new_state.each do |k, v|
12
+ state(request, key)[k] = v
13
+ end
14
+ end
15
+
16
+ def self.store_state(request, key, new_state = {})
17
+ VIEW_COMPONENT_REFLEX_MEMORY_STATE[request.session.id.to_s] ||= {}
18
+ VIEW_COMPONENT_REFLEX_MEMORY_STATE[request.session.id.to_s][key] ||= {}
19
+ new_state.each do |k, v|
20
+ VIEW_COMPONENT_REFLEX_MEMORY_STATE[request.session.id.to_s][key][k] = v
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -1,3 +1,3 @@
1
1
  module ViewComponentReflex
2
- VERSION = '1.6.1'
2
+ VERSION = '1.7.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: view_component_reflex
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.1
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua LeBlanc
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-26 00:00:00.000000000 Z
11
+ date: 2020-07-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -71,6 +71,7 @@ files:
71
71
  - app/components/view_component_reflex/component.rb
72
72
  - lib/view_component_reflex.rb
73
73
  - lib/view_component_reflex/engine.rb
74
+ - lib/view_component_reflex/state_adapter/memory.rb
74
75
  - lib/view_component_reflex/state_adapter/session.rb
75
76
  - lib/view_component_reflex/version.rb
76
77
  homepage: https://github.com/joshleblanc/view_component_reflex