Class: CrudComponents::DynamicColumn
- Inherits:
-
Object
- Object
- CrudComponents::DynamicColumn
- Defined in:
- lib/crud_components/dynamic_column.rb
Overview
A column whose data lives outside the model's own table — a user-defined
property kept in a separate store (definition + value tables, a JSONB blob,
an external API). The model knows nothing about it; you build one per request
from wherever your custom properties live and hand it to crud_collection
via extra_columns:.
CrudComponents::DynamicColumn.new(:priority,
label: 'Priority', as: :number,
if: -> { can?(:read, prop) }, # same gate as a field's if:
preload: ->(records) { # batch-load once per page (no N+1)
PropertyValue.where(definition: prop, subject: records).index_by(&:subject_id)
},
sort: ->(scope, dir) { ... }, # optional — omit for display-only
filter: ->(scope, geq:, leq:) { ... }) { |record, loaded| loaded[record.id]&.value }
The block is the value resolver: |record| or |record, loaded|, where
loaded is whatever preload: returned. It returns a plain value that the
as: renderer (or, with no as:, the value's type) displays — exactly like
a computed field.
sort: is the same facet block the DSL takes. filter: reaches SQL too, but
the control it renders follows the column's type: a filter: block that
declares keyword params (geq:/leq:, eq:, contains:) filters as the
as: type does — a :number column gets a number range, :date a date range,
:boolean a yes/no select. Override the filter type with filter_as: (and
filter_choices: for a select) when it differs from as:. A positional
filter: ->(scope, value) block stays a plain text filter. Supply filter:/
sort: only when the data is reachable in SQL, otherwise the column is
display-only and never reaches the query layer.
A dynamic column often is a domain object (a mail, a resource), so its
header can carry a link and its own bulk actions, rendered in the <th>:
CrudComponents::DynamicColumn.new(:mail_42,
label: 'Welcome mail',
header: -> { link_to mail.name, mail }, # HTML-safe String or a view-context block
header_actions: [ # the same Action API as row/collection actions
CrudComponents::Action.new(:send_all, icon: 'send', method: :post) { send_all_path(mail) },
CrudComponents::Action.new(:unschedule_all, method: :post) { unschedule_all_path(mail) }
],
preload: ->(records) { ... }) { |record, loaded| loaded[record.id] }
header: replaces the plain human_name text (a String is rendered as-is —
mark it html_safe if it carries markup; a block is instance_execed in the
view, so it may call link_to and friends). header_actions: renders after
the header; an on: :selection action acts on the ticked rows (it submits the
shared select-form, so its path closes over the column's object × the
selection), while any other action renders as a plain link/button.
header:/header_actions: are not consumed here — they ride along in options
and are read off the field by Fields::Base, exactly like a declared
attribute's attribute :x, header_actions: […].
Constant Summary collapse
- FACET_KEYS =
Keys consumed here; everything else (as:, if:, label:, header:, header_actions:, unit:, digits:, …) flows into
optionsjust like a declared attribute's options. %i[filter sort render].freeze
Instance Attribute Summary collapse
-
#facets ⇒ Object
readonly
Returns the value of attribute facets.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
-
#options ⇒ Object
readonly
Returns the value of attribute options.
-
#preload_block ⇒ Object
readonly
Returns the value of attribute preload_block.
-
#value_block ⇒ Object
readonly
Returns the value of attribute value_block.
Instance Method Summary collapse
-
#initialize(name, preload: nil, **opts, &value_block) ⇒ DynamicColumn
constructor
A new instance of DynamicColumn.
-
#to_field(model) ⇒ Object
A request-scoped field bound to
model.
Constructor Details
#initialize(name, preload: nil, **opts, &value_block) ⇒ DynamicColumn
Returns a new instance of DynamicColumn.
62 63 64 65 66 67 68 |
# File 'lib/crud_components/dynamic_column.rb', line 62 def initialize(name, preload: nil, **opts, &value_block) @name = name.to_sym @value_block = value_block @preload_block = preload @facets = opts.slice(*FACET_KEYS).compact @options = opts.except(*FACET_KEYS) end |
Instance Attribute Details
#facets ⇒ Object (readonly)
Returns the value of attribute facets.
55 56 57 |
# File 'lib/crud_components/dynamic_column.rb', line 55 def facets @facets end |
#name ⇒ Object (readonly)
Returns the value of attribute name.
55 56 57 |
# File 'lib/crud_components/dynamic_column.rb', line 55 def name @name end |
#options ⇒ Object (readonly)
Returns the value of attribute options.
55 56 57 |
# File 'lib/crud_components/dynamic_column.rb', line 55 def @options end |
#preload_block ⇒ Object (readonly)
Returns the value of attribute preload_block.
55 56 57 |
# File 'lib/crud_components/dynamic_column.rb', line 55 def preload_block @preload_block end |
#value_block ⇒ Object (readonly)
Returns the value of attribute value_block.
55 56 57 |
# File 'lib/crud_components/dynamic_column.rb', line 55 def value_block @value_block end |
Instance Method Details
#to_field(model) ⇒ Object
A request-scoped field bound to model. Not memoized on the Structure, so
it may carry the per-request value cache (see Fields::DynamicField).
72 73 74 |
# File 'lib/crud_components/dynamic_column.rb', line 72 def to_field(model) Fields::DynamicField.new(self, model) end |