Class: Hibiki::Rails::Generators::ScaffoldColumn
- Inherits:
-
Object
- Object
- Hibiki::Rails::Generators::ScaffoldColumn
- Defined in:
- lib/generators/hibiki/rails/scaffold_schema.rb
Overview
One column of a scaffolded resource.
Both sources wrap a ::Rails::Generators::GeneratedAttribute, even when the facts came from a real schema, because railties' own per-version knowledge rides on it — #field_type, requiredness, index handling — and tracking that by hand is how a generated _form stops matching the Rails it runs on. Synthesizing the attribute on the introspection path buys that for both paths at once.
Constant Summary collapse
- TEXTUAL =
Types that can carry a LIKE term.
%i[string text].freeze
- COMPARABLE =
Types a sort control can order by. Text is excluded deliberately: an unbounded blob is a meaningless sort key, and §11.6 wants an index per sortable column. Boolean is excluded because two values is a filter, not an order.
%i[string integer decimal float date datetime time].freeze
- TAG_HELPERS =
Which *_tag helper renders the control in the channel-backed form. These are the OLD names: Rails 8.1 renamed them to #textarea_tag / #checkbox_tag and kept these as aliases. Originally that was the only spelling valid across a matrix that included 7.1/7.2; with the floor now at 8.0 both spellings work, and these stay because changing them would rewrite generated output — a byte-diff against every reference and test app — to buy nothing. Revisit if Rails ever drops the aliases; that is the one thing that would make it worth the churn.
{ string: :text_field_tag, text: :text_area_tag, integer: :number_field_tag, decimal: :text_field_tag, float: :text_field_tag, date: :date_field_tag, datetime: :datetime_field_tag, time: :time_field_tag, boolean: :check_box_tag }.freeze
- KEYSTROKE_TYPES =
Which DOM event a control reports on. Free text and numbers report per keystroke (Helpers#on debounces :input at 250ms) so live validation and dirty? follow the typing; selects, dates and checkboxes have no intermediate states worth reporting.
%i[string text integer decimal float].freeze
- COMPARISONS =
AR's own comparison vocabulary, mapped to the negation that makes an error message true. Using AR's wording means the message a field shows BEFORE a round trip is the message the record produces after one.
{ greater_than: "<=", greater_than_or_equal_to: "<", less_than: ">=", less_than_or_equal_to: ">" }.freeze
- CONDITIONAL =
Options that make a validator run only sometimes. Whatever they depend on is a fact about the RECORD, which a form signal does not have — so a validator carrying one of these contributes nothing before a round trip and is dropped rather than guessed at. It still runs at #commit and still lands in #errors.
%i[if unless on].freeze
Instance Attribute Summary collapse
-
#attr ⇒ Object
readonly
Returns the value of attribute attr.
-
#reflection ⇒ Object
readonly
Returns the value of attribute reflection.
-
#validators ⇒ Object
readonly
Returns the value of attribute validators.
Instance Method Summary collapse
- #association_class_name ⇒ Object
- #association_name ⇒ Object
- #belongs_to? ⇒ Boolean
-
#display_reader ⇒ Object
What the row template prints, as source text: a belongs_to prints the association's label (&. mirrors a missing parent, like the old allow_nil delegate did), a scalar its own reader.
- #filterable? ⇒ Boolean
- #form_field_helper ⇒ Object
-
#html_bounds ⇒ Object
min:/max:for a number field, from the same numericality validator that produces the live error. - #human_name ⇒ Object
-
#initialize(attr:, required: false, reflection: nil, label_column: nil, validators: []) ⇒ ScaffoldColumn
constructor
A new instance of ScaffoldColumn.
-
#label_column ⇒ Object
Which column of the ASSOCIATED table a select displays.
-
#live_error_clause ⇒ Object
The right-hand side of one entry in the form's live_errors derived, or nil when nothing about this column is knowable before a round trip.
-
#name ⇒ Object
From the reflection when there is one:
belongs_to :author, foreign_key: :writer_idis the case where the association's name and its column genuinely disagree, and GeneratedAttribute can only guess. - #numeric? ⇒ Boolean
- #options_local ⇒ Object
- #required? ⇒ Boolean
- #searchable? ⇒ Boolean
- #sortable? ⇒ Boolean
- #tag_event ⇒ Object
- #tag_field_helper ⇒ Object
- #type ⇒ Object
Constructor Details
#initialize(attr:, required: false, reflection: nil, label_column: nil, validators: []) ⇒ ScaffoldColumn
Returns a new instance of ScaffoldColumn.
66 67 68 69 70 71 72 73 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 66 def initialize(attr:, required: false, reflection: nil, label_column: nil, validators: []) @attr = attr @required = required @reflection = reflection @label_column = label_column @validators = validators end |
Instance Attribute Details
#attr ⇒ Object (readonly)
Returns the value of attribute attr.
64 65 66 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 64 def attr @attr end |
#reflection ⇒ Object (readonly)
Returns the value of attribute reflection.
64 65 66 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 64 def reflection @reflection end |
#validators ⇒ Object (readonly)
Returns the value of attribute validators.
64 65 66 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 64 def validators @validators end |
Instance Method Details
#association_class_name ⇒ Object
89 90 91 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 89 def association_class_name @association_class_name ||= reflection&.class_name || attr.name.camelize end |
#association_name ⇒ Object
87 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 87 def association_name = @association_name ||= (reflection&.name || attr.name).to_sym |
#belongs_to? ⇒ Boolean
78 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 78 def belongs_to? = !reflection.nil? || attr.reference? |
#display_reader ⇒ Object
What the row template prints, as source text: a belongs_to prints the association's label (&. mirrors a missing parent, like the old allow_nil delegate did), a scalar its own reader.
103 104 105 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 103 def display_reader belongs_to? ? "#{association_name}&.#{label_column}" : name.to_s end |
#filterable? ⇒ Boolean
118 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 118 def filterable? = type == :boolean |
#form_field_helper ⇒ Object
108 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 108 def form_field_helper = belongs_to? ? :collection_select : attr.field_type |
#html_bounds ⇒ Object
min: / max: for a number field, from the same numericality
validator that produces the live error. Nothing is invented: a column
with no validator gets no bounds.
125 126 127 128 129 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 125 def html_bounds return {} unless numeric? { min: lower_bound, max: upper_bound }.compact end |
#human_name ⇒ Object
77 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 77 def human_name = attr.human_name |
#label_column ⇒ Object
Which column of the ASSOCIATED table a select displays. Only the
introspection path can know it; the attribute path has no second
schema to look at, so it guesses :name and the generator's
post-install output says so out loud. Defaulted here rather than at
each call site — a nil leaking into a template emits order(:).
98 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 98 def label_column = @label_column || :name |
#live_error_clause ⇒ Object
The right-hand side of one entry in the form's live_errors derived, or nil when nothing about this column is knowable before a round trip. Clauses are OR-ed so a column can be both required and bounded; with a single clause this is byte-identical to a hand-written entry.
135 136 137 138 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 135 def live_error_clause clauses = [presence_clause, *numericality_clauses, length_clause].compact clauses.join(" || ") unless clauses.empty? end |
#name ⇒ Object
From the reflection when there is one: belongs_to :author, foreign_key: :writer_id is the case where the association's name and
its column genuinely disagree, and GeneratedAttribute can only guess.
83 84 85 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 83 def name @name ||= (reflection ? reflection.foreign_key : attr.column_name).to_sym end |
#numeric? ⇒ Boolean
120 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 120 def numeric? = %i[integer decimal float].include?(type) |
#options_local ⇒ Object
107 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 107 def = :"#{association_name}_options" |
#required? ⇒ Boolean
76 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 76 def required? = @required |
#searchable? ⇒ Boolean
117 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 117 def searchable? = !belongs_to? && TEXTUAL.include?(type) |
#sortable? ⇒ Boolean
119 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 119 def sortable? = !belongs_to? && COMPARABLE.include?(type) |
#tag_event ⇒ Object
111 112 113 114 115 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 111 def tag_event return :change if belongs_to? KEYSTROKE_TYPES.include?(type) ? :input : :change end |
#tag_field_helper ⇒ Object
109 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 109 def tag_field_helper = belongs_to? ? :select_tag : TAG_HELPERS.fetch(type, :text_field_tag) |
#type ⇒ Object
75 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 75 def type = attr.type |