Class: TurboReflex::StateManager
- Inherits:
-
Object
- Object
- TurboReflex::StateManager
- Includes:
- ActiveModel::Dirty
- Defined in:
- lib/turbo_reflex/state_manager.rb
Overview
Class used to hold ephemeral state related to the rendered UI.
Examples:
-
Sidebar open/closed state
-
Tree view open/closed state
-
Accordion collapsed/expanded state
-
Customized layout / presentation
-
Applied data filters
-
Number of data rows to display etc.
Instance Attribute Summary collapse
-
#cookie_data ⇒ Object
readonly
Returns the value of attribute cookie_data.
-
#header_data ⇒ Object
readonly
Returns the value of attribute header_data.
-
#server_data ⇒ Object
readonly
Returns the value of attribute server_data.
Class Method Summary collapse
- .add_state_override_block(controller_name, block) ⇒ Object
- .state_override_block(controller) ⇒ Object
- .state_override_blocks ⇒ Object
Instance Method Summary collapse
- #[](*keys, default: nil) ⇒ Object
- #[]=(*keys, value) ⇒ Object
- #clear ⇒ Object
-
#initialize(runner) ⇒ StateManager
constructor
A new instance of StateManager.
- #ordinal_payload ⇒ Object
- #payload ⇒ Object
- #provisional_state ⇒ Object (also: #now)
- #write_cookie ⇒ Object
Constructor Details
#initialize(runner) ⇒ StateManager
Returns a new instance of StateManager.
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/turbo_reflex/state_manager.rb', line 44 def initialize(runner) @runner = runner begin @state = TurboReflex::State.new() # server state as stored in the cookie rescue => error Rails.logger.error "Failed to construct TurboReflex::State! #{error.}" @state = TurboReflex::State.new end # State the server used to render the page last time = state.to_h # State managed by the server on the backend (redis cache etc.) # SEE: `TurboReflex::StateManager.state_override_block` server_state_hash = {} # State the client expects... related to optimistic UI updates # i.e. Changes made on the client before making this request header_state_hash = {} # Apply server state overrides (i.e. state stored in databases like Redis, Postgres, etc...) if TurboReflex.config.apply_server_state_overrides begin state_override_block = self.class.state_override_block(runner.controller) if state_override_block server_state_hash = runner.controller.instance_eval(&state_override_block).with_indifferent_access server_state_hash.each { |key, val| self[key] = val } end rescue => error Rails.logger.error "Failed to apply `state_override_block` configured in #{runner.controller.class.name} to TurboReflex::State! #{error.}" end end # Apply client state overrides (i.e. optimistic state) # NOTE: Client state HTTP headers are only sent if/when state has changed on the client (only the changes are sent). # This prevents race conditions (state mismatch) caused when frame and XHR requests emit immediately # before the <meta id="turbo-reflex"> has been updated with the latest state from the server. if TurboReflex.config.apply_client_state_overrides begin header_state_hash = TurboReflex::State.deserialize_base64(header).with_indifferent_access header_state_hash.each { |key, val| self[key] = val } rescue => error Rails.logger.error "Failed to apply client state from HTTP headers to TurboReflex::State! #{error.}" end end @cookie_data = @header_data = header_state_hash @server_data = server_state_hash rescue => error Rails.logger.error "Failed to construct TurboReflex::State! #{error.}" ensure @state ||= TurboReflex::State.new end |
Instance Attribute Details
#cookie_data ⇒ Object (readonly)
Returns the value of attribute cookie_data.
42 43 44 |
# File 'lib/turbo_reflex/state_manager.rb', line 42 def @cookie_data end |
#header_data ⇒ Object (readonly)
Returns the value of attribute header_data.
42 43 44 |
# File 'lib/turbo_reflex/state_manager.rb', line 42 def header_data @header_data end |
#server_data ⇒ Object (readonly)
Returns the value of attribute server_data.
42 43 44 |
# File 'lib/turbo_reflex/state_manager.rb', line 42 def server_data @server_data end |
Class Method Details
.add_state_override_block(controller_name, block) ⇒ Object
25 26 27 |
# File 'lib/turbo_reflex/state_manager.rb', line 25 def add_state_override_block(controller_name, block) state_override_blocks[controller_name] = block end |
.state_override_block(controller) ⇒ Object
29 30 31 32 33 |
# File 'lib/turbo_reflex/state_manager.rb', line 29 def state_override_block(controller) return nil if state_override_blocks.blank? ancestor = controller.class.ancestors.find { |a| state_override_blocks[a.name] } state_override_blocks[ancestor.name] end |
.state_override_blocks ⇒ Object
21 22 23 |
# File 'lib/turbo_reflex/state_manager.rb', line 21 def state_override_blocks @state_overrides ||= {} end |
Instance Method Details
#[](*keys, default: nil) ⇒ Object
102 103 104 |
# File 'lib/turbo_reflex/state_manager.rb', line 102 def [](*keys, default: nil) state.read(*keys, default: default) end |
#[]=(*keys, value) ⇒ Object
106 107 108 109 |
# File 'lib/turbo_reflex/state_manager.rb', line 106 def []=(*keys, value) state_will_change! if value != self[*keys] value.nil? ? state.delete(*keys) : state.write(*keys, value) end |
#clear ⇒ Object
117 118 119 120 |
# File 'lib/turbo_reflex/state_manager.rb', line 117 def clear provisional_state.clear state.clear end |
#ordinal_payload ⇒ Object
128 129 130 131 132 133 |
# File 'lib/turbo_reflex/state_manager.rb', line 128 def ordinal_payload provisional_state.clear state.shrink! state.prune! max_bytesize: TurboReflex.config. state.ordinal_payload end |
#payload ⇒ Object
122 123 124 125 126 |
# File 'lib/turbo_reflex/state_manager.rb', line 122 def payload provisional_state.clear state.shrink! state.payload end |
#provisional_state ⇒ Object Also known as: now
111 112 113 |
# File 'lib/turbo_reflex/state_manager.rb', line 111 def provisional_state @provisional_state ||= TurboReflex::ProvisionalState.new(self) end |
#write_cookie ⇒ Object
135 136 137 138 139 140 141 |
# File 'lib/turbo_reflex/state_manager.rb', line 135 def return unless changed? || .blank? .signed["turbo_reflex.state"] = {value: ordinal_payload, path: "/", expires: 1.day.from_now} changes_applied rescue => error Rails.logger.error "Failed to write the TurboReflex::State cookie! #{error.}" end |