Dynamic definitions (dynamic models, activity logs, external identifiers) can include
attributes backed by a json or jsonb database column. Rather than exposing raw JSON
to the user, ReStructure presents these columns as a YAML code editor, since YAML is
more compact and readable for hand-editing hashes and arrays than JSON is.
This document describes how the display (JSON/jsonb → YAML) and save (YAML → JSON/jsonb) translation works, and how it is wired together.
app/views/common_templates/edit_fields/_column_type_jsonb.html.erbis the template used to render the field. It is matched automatically by column type: a field backed by ajsonbcolumn resolves tocolumn_type_jsonb, and a field backed by ajsoncolumn resolves tocolumn_type_json.app/views/common_templates/edit_fields/_column_type_json.html.erbsimply renders the_column_type_jsonbpartial, so both column types share one implementation.- The current attribute value is passed to
Dynamic::FieldEditAs::ColTypeJson.display_value, which dumps aHashorArrayvalue to a YAML string withString.yaml_dump, and renders it into acode-editor-yamltextarea (a CodeMirror YAML editor keyed bydata-code-editor-type: 'yaml'). Any other value (nil, blank string, etc) renders as an empty textarea. This distinction matters because#present?isfalsefor an emptyHash/Arrayas well as for a blank value - using#present?to decide whether to dump would make a stored{}or[]indistinguishable from "no value", both rendering blank and then being cleared tonilif the form were resubmitted unchanged.
- On submit, the field arrives as a plain YAML-formatted string parameter, matching whatever the user typed into the editor.
Dynamic::FieldEditAs::Handler#translate_to_persistable(seeapp/models/dynamic/field_edit_as/handler.rb) is called fromMasterHandler#translate_params_to_persistable(and applied likewise to any embedded item) before the params are assigned to the model.- For each attribute, the handler determines its
edit_asfield type - defaulting to"col_type_#{column.type}"when no explicitfield_options.edit_as.field_typeis configured. This yieldscol_type_jsonforjsoncolumns andcol_type_jsonbforjsonbcolumns. Handler::TransformFieldTypesonly listscol_type_json, and the match against a field's resolved type is done withinclude?(substring match), not equality. This meanscol_type_jsonb.include?(col_type_json) istrue, so bothjsonandjsonbcolumns are routed to the same translation class.Dynamic::FieldEditAs::ColTypeJson.persistable_value(seeapp/models/dynamic/field_edit_as/col_type_json.rb) parses the submitted YAML string withYAML.safe_load. It accepts the parsed value only when it is already a top-levelHashorArray; that object is what gets persisted into the json/jsonb column.
Non-blank YAML documents must have a top-level Hash or Array. Any other value
(including a bare scalar, null, false, malformed YAML, or YAML aliases rejected
by YAML.safe_load) raises an FphsException from ColTypeJson.persistable_value.
A blank field returns nil, allowing the normal model assignment to clear the column.
A YAML document that parses to an empty string (for example --- ''\n) is also treated
as blank and returns nil, rather than raising. This specifically covers the display
template rendering a blank/absent value: String.yaml_dump('') produces the YAML
document --- ''\n rather than an empty string, so resubmitting the field unchanged
when it started blank must not raise.
app/models/dynamic/field_edit_as/handler.rbapp/models/dynamic/field_edit_as/col_type_json.rbapp/views/common_templates/edit_fields/_column_type_json.html.erbapp/views/common_templates/edit_fields/_column_type_jsonb.html.erb- Admin field types reference - see the
column_type_json/column_type_jsonbrows in the Column Type Templates table.