Class: StimulusGridRails::Column
- Inherits:
-
Object
- Object
- StimulusGridRails::Column
- Defined in:
- lib/stimulus_grid_rails/column.rb
Overview
One column on a Grid. Captures everything the server needs to authorise, coerce, validate, and broadcast changes for this field — plus everything the client needs to choose an editor and render a cell.
Created via the ‘column` DSL inside an ApplicationGrid subclass; not instantiated directly. See StimulusGridRails::Grid for usage.
Constant Summary collapse
- TYPES =
%i[string text integer bigint decimal money boolean enum date datetime reference].freeze
Instance Attribute Summary collapse
-
#cell_editor ⇒ Object
readonly
Returns the value of attribute cell_editor.
-
#cell_renderer ⇒ Object
readonly
Returns the value of attribute cell_renderer.
-
#concurrency ⇒ Object
readonly
Returns the value of attribute concurrency.
-
#depends_on ⇒ Object
readonly
Returns the value of attribute depends_on.
-
#editor ⇒ Object
readonly
Returns the value of attribute editor.
-
#editor_config ⇒ Object
readonly
Returns the value of attribute editor_config.
-
#enum_values ⇒ Object
readonly
Returns the value of attribute enum_values.
-
#header ⇒ Object
readonly
Returns the value of attribute header.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#pinned ⇒ Object
readonly
Returns the value of attribute pinned.
-
#type ⇒ Object
readonly
Returns the value of attribute type.
-
#validators ⇒ Object
readonly
Returns the value of attribute validators.
-
#width ⇒ Object
readonly
Returns the value of attribute width.
Instance Method Summary collapse
- #cascades? ⇒ Boolean
-
#client_data_attrs(row, user) ⇒ Object
Serialized into the rendered cell’s data-* attributes so the client-side editor controller can mount the right editor with the right config.
-
#coerce(raw) ⇒ Object
Coerce a string value (from a form submission) to this column’s Ruby type.
- #computed? ⇒ Boolean
-
#editable_for?(row, user) ⇒ Boolean
Per-row, per-user editable check.
- #editable_static? ⇒ Boolean
-
#filter_predicate(arel_table, criteria) ⇒ Object
Arel predicate for a per-column filter.
-
#header_data_attrs ⇒ Object
Serialized into the column’s <th> so header_cell_controller picks it up.
-
#initialize(name, type:, editable: false, editor: nil, editor_config: {}, enum_values: nil, concurrency: :last_write_wins, computed: false, depends_on: [], validate: nil, header: nil, width: nil, pinned: nil, cell_renderer: nil, cell_editor: nil, sortable: true, filterable: true, searchable: nil) ⇒ Column
constructor
A new instance of Column.
-
#search_predicate(arel_table, term) ⇒ Object
Arel predicate for the global search term, or nil if this column doesn’t participate.
- #searchable? ⇒ Boolean
-
#validate(value, row) ⇒ Object
Run client-defined validators.
Constructor Details
#initialize(name, type:, editable: false, editor: nil, editor_config: {}, enum_values: nil, concurrency: :last_write_wins, computed: false, depends_on: [], validate: nil, header: nil, width: nil, pinned: nil, cell_renderer: nil, cell_editor: nil, sortable: true, filterable: true, searchable: nil) ⇒ Column
Returns a new instance of Column.
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/stimulus_grid_rails/column.rb', line 15 def initialize(name, type:, editable: false, editor: nil, editor_config: {}, enum_values: nil, concurrency: :last_write_wins, computed: false, depends_on: [], validate: nil, header: nil, width: nil, pinned: nil, cell_renderer: nil, cell_editor: nil, sortable: true, filterable: true, searchable: nil) raise ArgumentError, "Unknown column type #{type.inspect}" unless TYPES.include?(type) @name = name.to_sym @type = type @editable = editable # may be `true`, `false`, or a Proc(row, user) @editor = editor || default_editor_for(type) @editor_config = editor_config @enum_values = enum_values @concurrency = concurrency @computed = computed @depends_on = Array(depends_on) @validators = Array(validate) @header = header || name.to_s.humanize @width = width @pinned = pinned @cell_renderer = cell_renderer @cell_editor = cell_editor @sortable = sortable @filterable = filterable # Global search defaults to text-ish columns; numeric/date/boolean opt in. @searchable = searchable.nil? ? %i[string text enum reference].include?(type) : searchable end |
Instance Attribute Details
#cell_editor ⇒ Object (readonly)
Returns the value of attribute cell_editor.
11 12 13 |
# File 'lib/stimulus_grid_rails/column.rb', line 11 def cell_editor @cell_editor end |
#cell_renderer ⇒ Object (readonly)
Returns the value of attribute cell_renderer.
11 12 13 |
# File 'lib/stimulus_grid_rails/column.rb', line 11 def cell_renderer @cell_renderer end |
#concurrency ⇒ Object (readonly)
Returns the value of attribute concurrency.
11 12 13 |
# File 'lib/stimulus_grid_rails/column.rb', line 11 def concurrency @concurrency end |
#depends_on ⇒ Object (readonly)
Returns the value of attribute depends_on.
11 12 13 |
# File 'lib/stimulus_grid_rails/column.rb', line 11 def depends_on @depends_on end |
#editor ⇒ Object (readonly)
Returns the value of attribute editor.
11 12 13 |
# File 'lib/stimulus_grid_rails/column.rb', line 11 def editor @editor end |
#editor_config ⇒ Object (readonly)
Returns the value of attribute editor_config.
11 12 13 |
# File 'lib/stimulus_grid_rails/column.rb', line 11 def editor_config @editor_config end |
#enum_values ⇒ Object (readonly)
Returns the value of attribute enum_values.
11 12 13 |
# File 'lib/stimulus_grid_rails/column.rb', line 11 def enum_values @enum_values end |
#header ⇒ Object (readonly)
Returns the value of attribute header.
11 12 13 |
# File 'lib/stimulus_grid_rails/column.rb', line 11 def header @header end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
11 12 13 |
# File 'lib/stimulus_grid_rails/column.rb', line 11 def name @name end |
#pinned ⇒ Object (readonly)
Returns the value of attribute pinned.
11 12 13 |
# File 'lib/stimulus_grid_rails/column.rb', line 11 def pinned @pinned end |
#type ⇒ Object (readonly)
Returns the value of attribute type.
11 12 13 |
# File 'lib/stimulus_grid_rails/column.rb', line 11 def type @type end |
#validators ⇒ Object (readonly)
Returns the value of attribute validators.
11 12 13 |
# File 'lib/stimulus_grid_rails/column.rb', line 11 def validators @validators end |
#width ⇒ Object (readonly)
Returns the value of attribute width.
11 12 13 |
# File 'lib/stimulus_grid_rails/column.rb', line 11 def width @width end |
Instance Method Details
#cascades? ⇒ Boolean
57 |
# File 'lib/stimulus_grid_rails/column.rb', line 57 def cascades? = !@depends_on.empty? |
#client_data_attrs(row, user) ⇒ Object
Serialized into the rendered cell’s data-* attributes so the client-side editor controller can mount the right editor with the right config.
130 131 132 133 134 135 136 137 138 139 |
# File 'lib/stimulus_grid_rails/column.rb', line 130 def client_data_attrs(row, user) attrs = { "data-col-id" => name, "data-editor" => @editor, } attrs["data-editable"] = "true" if editable_for?(row, user) attrs["data-enum-values"] = JSON.generate(@enum_values) if @enum_values attrs["data-editor-config"] = JSON.generate(@editor_config) unless @editor_config.empty? attrs end |
#coerce(raw) ⇒ Object
Coerce a string value (from a form submission) to this column’s Ruby type. Returns [value, error] — error is a string if coercion failed.
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/stimulus_grid_rails/column.rb', line 61 def coerce(raw) case @type when :string, :text, :enum, :reference then [raw.to_s, nil] when :integer, :bigint Integer(raw.to_s, 10).then { |i| [i, nil] } when :decimal, :money [BigDecimal(raw.to_s), nil] when :boolean [%w[1 true yes on t].include?(raw.to_s.downcase), nil] when :date [Date.parse(raw.to_s), nil] when :datetime [Time.zone.parse(raw.to_s), nil] else [raw, nil] end rescue ArgumentError, TypeError => e [nil, "invalid #{@type}: #{e.}"] end |
#computed? ⇒ Boolean
56 |
# File 'lib/stimulus_grid_rails/column.rb', line 56 def computed? = @computed |
#editable_for?(row, user) ⇒ Boolean
Per-row, per-user editable check. RAILS.md §17 — server re-evaluates on every PATCH (never trust the client’s data-editable attribute).
44 45 46 47 48 49 50 |
# File 'lib/stimulus_grid_rails/column.rb', line 44 def editable_for?(row, user) case @editable when true, false then @editable when Proc then !!@editable.call(row, user) else !!@editable end end |
#editable_static? ⇒ Boolean
52 53 54 |
# File 'lib/stimulus_grid_rails/column.rb', line 52 def editable_static? @editable == true end |
#filter_predicate(arel_table, criteria) ⇒ Object
Arel predicate for a per-column filter. ‘criteria` mirrors the client filterModel shape: { “type” => op, “value” => v, “value2” => v2 }. Returns nil for computed/unknown columns or unparseable values.
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/stimulus_grid_rails/column.rb', line 95 def filter_predicate(arel_table, criteria) return nil if @computed || name.to_s.start_with?("_") col = arel_table[@name] op = (criteria["type"] || criteria[:type]).to_s raw = criteria["value"] || criteria[:value] raw2 = criteria["value2"] || criteria[:value2] case @type when :string, :text, :enum, :reference text_predicate(col, op, raw.to_s) when :integer, :bigint, :decimal, :money numeric_predicate(col, op, raw, raw2) when :date, :datetime date_predicate(col, op, raw, raw2) when :boolean v, err = coerce(raw) err ? nil : col.eq(v) end end |
#header_data_attrs ⇒ Object
Serialized into the column’s <th> so header_cell_controller picks it up.
142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/stimulus_grid_rails/column.rb', line 142 def header_data_attrs { "data-controller" => "header-cell", "data-header-cell-field-value" => name, "data-header-cell-type-value" => header_cell_type, "data-header-cell-sortable-value" => @sortable.to_s, "data-header-cell-filter-value" => (@filterable ? filter_type_for_client : nil), "data-header-cell-editable-value" => editable_static?.to_s, "data-header-cell-pinned-value" => @pinned, "data-header-cell-width-value" => @width, "data-header-cell-cell-renderer-value" => @cell_renderer, "data-header-cell-cell-editor-value" => @cell_editor, }.compact end |
#search_predicate(arel_table, term) ⇒ Object
Arel predicate for the global search term, or nil if this column doesn’t participate. Case-insensitive contains over the column’s text. Computed and action columns never match (no DB column to query).
86 87 88 89 90 |
# File 'lib/stimulus_grid_rails/column.rb', line 86 def search_predicate(arel_table, term) return nil unless searchable? pattern = "%#{like_escape(term.to_s.downcase)}%" arel_table[@name].lower.matches(pattern) end |
#searchable? ⇒ Boolean
81 |
# File 'lib/stimulus_grid_rails/column.rb', line 81 def searchable? = @searchable && !@computed && !name.to_s.start_with?("_") |
#validate(value, row) ⇒ Object
Run client-defined validators. Returns Array of error strings.
116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/stimulus_grid_rails/column.rb', line 116 def validate(value, row) @validators.flat_map do |v| result = v.call(value, row) case result when nil, true then [] when String then [result] when Array then result else [result.to_s] end end end |