Class: TurboBoost::State::Manager
- Inherits:
-
Object
- Object
- TurboBoost::State::Manager
- Includes:
- ActiveModel::Dirty
- Defined in:
- lib/turbo_boost/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
-
#controller ⇒ Object
readonly
Returns the value of attribute controller.
-
#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
-
#cookies ⇒ Object
Same implementation as ActionController::Base but with public visibility.
-
#initialize(controller) ⇒ Manager
constructor
A new instance of Manager.
- #ordinal_payload ⇒ Object
- #payload ⇒ Object
- #provisional_state ⇒ Object (also: #now)
- #write_cookie ⇒ Object
Constructor Details
#initialize(controller) ⇒ Manager
Returns a new instance of Manager.
41 42 43 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 |
# File 'lib/turbo_boost/state/manager.rb', line 41 def initialize(controller) @controller = controller begin @state = TurboBoost::State.new() # server state as stored in the cookie rescue => error Rails.logger.error "Failed to construct TurboBoost::State! #{error.}" @state = TurboBoost::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: `TurboBoost::State::Manager.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 TurboBoost::Commands.config.apply_server_state_overrides begin state_override_block = self.class.state_override_block(controller) if state_override_block server_state_hash = 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 #{controller.class.name} to TurboBoost::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-boost"> has been updated with the latest state from the server. if TurboBoost::Commands.config.apply_client_state_overrides begin header_state_hash = TurboBoost::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 TurboBoost::State! #{error.}" end end @cookie_data = @header_data = header_state_hash @server_data = server_state_hash rescue => error Rails.logger.error "Failed to construct TurboBoost::State! #{error.}" ensure @state ||= TurboBoost::State.new end |
Instance Attribute Details
#controller ⇒ Object (readonly)
Returns the value of attribute controller.
39 40 41 |
# File 'lib/turbo_boost/state/manager.rb', line 39 def controller @controller end |
#cookie_data ⇒ Object (readonly)
Returns the value of attribute cookie_data.
39 40 41 |
# File 'lib/turbo_boost/state/manager.rb', line 39 def @cookie_data end |
#header_data ⇒ Object (readonly)
Returns the value of attribute header_data.
39 40 41 |
# File 'lib/turbo_boost/state/manager.rb', line 39 def header_data @header_data end |
#server_data ⇒ Object (readonly)
Returns the value of attribute server_data.
39 40 41 |
# File 'lib/turbo_boost/state/manager.rb', line 39 def server_data @server_data end |
Class Method Details
.add_state_override_block(controller_name, block) ⇒ Object
25 26 27 |
# File 'lib/turbo_boost/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_boost/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_boost/state/manager.rb', line 21 def state_override_blocks @state_overrides ||= {} end |
Instance Method Details
#[](*keys, default: nil) ⇒ Object
104 105 106 |
# File 'lib/turbo_boost/state/manager.rb', line 104 def [](*keys, default: nil) state.read(*keys, default: default) end |
#[]=(*keys, value) ⇒ Object
108 109 110 111 |
# File 'lib/turbo_boost/state/manager.rb', line 108 def []=(*keys, value) state_will_change! if value != self[*keys] value.nil? ? state.delete(*keys) : state.write(*keys, value) end |
#clear ⇒ Object
119 120 121 122 |
# File 'lib/turbo_boost/state/manager.rb', line 119 def clear provisional_state.clear state.clear end |
#cookies ⇒ Object
Same implementation as ActionController::Base but with public visibility
100 101 102 |
# File 'lib/turbo_boost/state/manager.rb', line 100 def controller.request. end |
#ordinal_payload ⇒ Object
130 131 132 133 134 135 |
# File 'lib/turbo_boost/state/manager.rb', line 130 def ordinal_payload provisional_state.clear state.shrink! state.prune! max_bytesize: TurboBoost::Commands.config. state.ordinal_payload end |
#payload ⇒ Object
124 125 126 127 128 |
# File 'lib/turbo_boost/state/manager.rb', line 124 def payload provisional_state.clear state.shrink! state.payload end |
#provisional_state ⇒ Object Also known as: now
113 114 115 |
# File 'lib/turbo_boost/state/manager.rb', line 113 def provisional_state @provisional_state ||= TurboBoost::State::ProvisionalState.new(self) end |
#write_cookie ⇒ Object
137 138 139 140 141 142 143 |
# File 'lib/turbo_boost/state/manager.rb', line 137 def return unless changed? || .blank? .signed["turbo_boost.state"] = {value: ordinal_payload, path: "/", expires: 1.day.from_now} changes_applied rescue => error Rails.logger.error "Failed to write the TurboBoost::State cookie! #{error.}" end |