Class: SolidObjects::ComponentsController
- Inherits:
-
ActionController::Base
- Object
- ActionController::Base
- SolidObjects::ComponentsController
- Defined in:
- app/controllers/solid_objects/components_controller.rb,
sig/generated/controllers/solid_objects/components_controller.rbs
Constant Summary collapse
- BATCH_LIMIT =
50
Instance Method Summary collapse
- #batch ⇒ void
-
#component_authorization_context(registrations) ⇒ Object
Callbacks written before batching accept only
controller:. - #component_frame(registration:, snapshot:, rendered:) ⇒ String
- #component_view_context ⇒ Object
- #newer_than_snapshot?(requested_revision, snapshot) ⇒ Boolean
- #refresh(payload) ⇒ void
- #refresh_batch(payload) ⇒ void
- #registration_payload(registration) ⇒ Hash[Symbol, untyped]
- #requested_revision_key ⇒ Array[Integer]
- #show ⇒ void
- #validate_single_batch!(registrations) ⇒ void
Instance Method Details
#batch ⇒ void
This method returns an undefined value.
17 18 19 |
# File 'app/controllers/solid_objects/components_controller.rb', line 17 def batch SolidObjects.instrument(:"component.batch_refreshed") { |payload| refresh_batch(payload) } end |
#component_authorization_context(registrations) ⇒ Object
Callbacks written before batching accept only controller:. Those keep
working; a callback that also accepts registrations: receives one
registration for a single refresh and all of them for a batch.
139 140 141 142 143 144 145 146 |
# File 'app/controllers/solid_objects/components_controller.rb', line 139 def (registrations) callable = SolidObjects.configuration. unless CallableKeywords.accepts?(callable, :registrations) return callable.call(controller: self) end callable.call(controller: self, registrations:) end |
#component_frame(registration:, snapshot:, rendered:) ⇒ String
186 187 188 189 |
# File 'app/controllers/solid_objects/components_controller.rb', line 186 def component_frame(registration:, snapshot:, rendered:) revision = "#{snapshot.instance_id}:#{snapshot.revision}" %(<turbo-frame id="#{registration.dom_id}" data-solid-objects-revision="#{revision}" data-solid-objects-refresh="#{registration.refresh_method}">#{rendered}</turbo-frame>).html_safe end |
#component_view_context ⇒ Object
175 176 177 178 179 180 181 182 183 |
# File 'app/controllers/solid_objects/components_controller.rb', line 175 def component_view_context if defined?(Rails) && Rails.application prepend_view_path(*Rails.application.paths["app/views"].existent) end view_context.tap do |context| context.extend(Rails.application.helpers) if defined?(Rails) && Rails.application end end |
#newer_than_snapshot?(requested_revision, snapshot) ⇒ Boolean
170 171 172 |
# File 'app/controllers/solid_objects/components_controller.rb', line 170 def newer_than_snapshot?(requested_revision, snapshot) (requested_revision <=> [ snapshot.instance_id, snapshot.revision ]) == 1 end |
#refresh(payload) ⇒ void
This method returns an undefined value.
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'app/controllers/solid_objects/components_controller.rb', line 98 def refresh(payload) registration = ComponentRegistration.from_token( params.require(:token) ) payload.merge!(registration_payload(registration)) requested_revision = requested_revision_key snapshot = ActorSnapshot.new(registration.reference) payload[:instance_id] = snapshot.instance_id payload[:revision] = snapshot.revision if newer_than_snapshot?(requested_revision, snapshot) payload[:outcome] = "conflict" return head :conflict end = ([ registration ]) rendered = ComponentRenderer.new( snapshot:, registration:, view_context: component_view_context, authorization_context: ).call response.headers["Cache-Control"] = "private, no-store" payload[:outcome] = "rendered" render html: component_frame(registration:, snapshot:, rendered:) rescue Unauthorized payload[:outcome] = "unauthorized" head :forbidden rescue UnknownComponent payload[:outcome] = "unknown_component" head :not_found rescue ActionController::ParameterMissing, ArgumentError, InvalidComponentToken payload[:outcome] = "invalid_token" head :bad_request end |
#refresh_batch(payload) ⇒ void
This method returns an undefined value.
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 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 |
# File 'app/controllers/solid_objects/components_controller.rb', line 24 def refresh_batch(payload) tokens = Array(params.require(:tokens)) raise ActionController::ParameterMissing, :tokens if tokens.empty? raise ArgumentError if tokens.length > BATCH_LIMIT registrations = tokens.map { |token| ComponentRegistration.from_token(token) } validate_single_batch!(registrations) requested_revision = requested_revision_key snapshot = ActorSnapshot.new(registrations.first.reference) payload.merge!( actor_type: snapshot.reference.actor_type, actor_id: snapshot.reference.actor_id, batch: registrations.first.batch, components: registrations.map(&:component_name), instance_id: snapshot.instance_id, revision: snapshot.revision ) if newer_than_snapshot?(requested_revision, snapshot) payload[:outcome] = "conflict" return head :conflict end = (registrations) frames = registrations.map do |registration| rendered = ComponentRenderer.new( snapshot:, registration:, view_context: component_view_context, authorization_context: ).call { "target" => registration.dom_id, "revision" => "#{snapshot.instance_id}:#{snapshot.revision}", "refresh_method" => registration.refresh_method, "html" => component_frame(registration:, snapshot:, rendered:) } end response.headers["Cache-Control"] = "private, no-store" payload[:outcome] = "rendered" render json: { "actor_type" => snapshot.reference.actor_type, "actor_id" => snapshot.reference.actor_id, "batch" => registrations.first.batch, "instance_id" => snapshot.instance_id, "revision" => snapshot.revision, "frames" => frames } rescue Unauthorized payload[:outcome] = "unauthorized" head :forbidden rescue UnknownComponent payload[:outcome] = "unknown_component" head :not_found rescue ActionController::ParameterMissing, ArgumentError, InvalidComponentToken payload[:outcome] = "invalid_token" head :bad_request end |
#registration_payload(registration) ⇒ Hash[Symbol, untyped]
149 150 151 152 153 154 155 156 157 158 |
# File 'app/controllers/solid_objects/components_controller.rb', line 149 def registration_payload(registration) { actor_type: registration.reference.actor_type, actor_id: registration.reference.actor_id, component_name: registration.component_name, component_key: registration.component_key, dependencies: registration.dependencies, refresh_method: registration.refresh_method } end |
#requested_revision_key ⇒ Array[Integer]
161 162 163 164 165 166 167 |
# File 'app/controllers/solid_objects/components_controller.rb', line 161 def requested_revision_key instance_id = Integer(params.fetch(:instance_id), 10) revision = Integer(params.fetch(:revision), 10) raise ArgumentError if instance_id.negative? || revision.negative? [ instance_id, revision ] end |
#show ⇒ void
This method returns an undefined value.
12 13 14 |
# File 'app/controllers/solid_objects/components_controller.rb', line 12 def show SolidObjects.instrument(:"component.refreshed") { |payload| refresh(payload) } end |
#validate_single_batch!(registrations) ⇒ void
This method returns an undefined value.
85 86 87 88 89 90 91 92 93 94 95 |
# File 'app/controllers/solid_objects/components_controller.rb', line 85 def validate_single_batch!(registrations) first = registrations.first raise ArgumentError unless first.batch return if registrations.all? do |registration| registration.batch == first.batch && registration.reference.actor_type == first.reference.actor_type && registration.reference.actor_id == first.reference.actor_id end raise ArgumentError end |