Module: StimulusGridRails

Defined in:
lib/stimulus_grid_rails.rb,
lib/stimulus_grid_rails/grid.rb,
lib/stimulus_grid_rails/column.rb,
lib/stimulus_grid_rails/engine.rb,
lib/stimulus_grid_rails/version.rb,
app/models/stimulus_grid_rails/audit.rb,
lib/stimulus_grid_rails/turbo_streams_helper.rb,
lib/stimulus_grid_rails/concerns/broadcastable.rb,
app/controllers/stimulus_grid_rails/base_controller.rb,
app/controllers/stimulus_grid_rails/rows_controller.rb,
app/controllers/stimulus_grid_rails/cells_controller.rb,
app/controllers/stimulus_grid_rails/history_controller.rb

Defined Under Namespace

Modules: Broadcastable, TurboStreams Classes: Audit, BaseController, CellsController, Column, Engine, Grid, HistoryController, RowsController

Constant Summary collapse

VERSION =
"0.1.0"

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.parent_controllerObject



19
20
21
# File 'lib/stimulus_grid_rails.rb', line 19

def parent_controller
  @parent_controller ||= "ApplicationController"
end

Class Method Details

.lookup_grid(resource) ⇒ Object



54
55
56
57
58
# File 'lib/stimulus_grid_rails.rb', line 54

def self.lookup_grid(resource)
  registry[resource.to_s] or
    raise ArgumentError, "No grid registered for resource #{resource.inspect}. " \
                         "Did you define a Grid subclass and reference it from a view?"
end

.mount_pathObject

Where the engine is mounted. The grid’s client-side endpoints are built from this, so it must match how you mount the engine:

# config/initializers/stimulus_grid_rails.rb
StimulusGridRails.mount_path = "/admin/grids"

# config/routes.rb
mount StimulusGridRails::Engine => StimulusGridRails.mount_path

Using the same value in both places keeps the browser requests and the routes in sync regardless of namespace/scope. Default “/grids”.



34
35
36
# File 'lib/stimulus_grid_rails.rb', line 34

def mount_path
  @mount_path || "/grids"
end

.mount_path=(path) ⇒ Object



38
39
40
# File 'lib/stimulus_grid_rails.rb', line 38

def mount_path=(path)
  @mount_path = path.to_s.sub(%r{/+\z}, "")   # strip trailing slash(es)
end

.register_grid(resource, klass) ⇒ Object



50
51
52
# File 'lib/stimulus_grid_rails.rb', line 50

def self.register_grid(resource, klass)
  registry[resource.to_s] = klass
end

.registryObject

Per-process registry of ApplicationGrid subclasses, keyed by ‘resource`. Populated lazily when a Grid subclass is instantiated, so the cells controller can resolve `/grids/:resource/…` back to the right Grid class.



46
47
48
# File 'lib/stimulus_grid_rails.rb', line 46

def self.registry
  @registry ||= {}
end

.streamables_for(resource, *extra) ⇒ Object

The streamables a grid’s broadcasts + subscription share. Tenant-scoped automatically. Pass extra view-scoping tokens (e.g. a signed view name) as needed.



76
77
78
# File 'lib/stimulus_grid_rails.rb', line 76

def self.streamables_for(resource, *extra)
  [tenant_stream_token, "sgr-grid:#{resource}", *extra].compact
end

.tenant_stream_tokenObject

Tenant-isolation token for stream names (RAILS.md §2). When the app uses ActsAsTenant and a tenant is set, this returns a per-tenant token so a broadcast for one tenant can never reach another tenant’s subscribers, even when grids share a logical stream name. Returns nil when not multi-tenant. Both the broadcaster (model callback) and the subscriber (turbo_stream_from in the view) run in the same request/tenant context, so they derive the same token and match.



67
68
69
70
71
# File 'lib/stimulus_grid_rails.rb', line 67

def self.tenant_stream_token
  return nil unless defined?(ActsAsTenant) && ActsAsTenant.respond_to?(:current_tenant)
  tenant = ActsAsTenant.current_tenant
  tenant ? "sgr-tenant:#{tenant.class.name}:#{tenant.id}" : nil
end