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 answers :textarea on Rails 8.1 and :text_area on 7.1, which is the difference between a generated _form that runs on this gem's floor and one that doesn't. 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 on purpose: Rails 8.1 renamed them to #textarea_tag / #checkbox_tag but kept these as aliases, while 7.1 and 7.2 have only these. One spelling valid across the whole supported matrix beats a version branch in a template.
{ 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 partial prints.
- #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.
63 64 65 66 67 68 69 70 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 63 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.
61 62 63 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 61 def attr @attr end |
#reflection ⇒ Object (readonly)
Returns the value of attribute reflection.
61 62 63 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 61 def reflection @reflection end |
#validators ⇒ Object (readonly)
Returns the value of attribute validators.
61 62 63 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 61 def validators @validators end |
Instance Method Details
#association_class_name ⇒ Object
86 87 88 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 86 def association_class_name @association_class_name ||= reflection&.class_name || attr.name.camelize end |
#association_name ⇒ Object
84 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 84 def association_name = @association_name ||= (reflection&.name || attr.name).to_sym |
#belongs_to? ⇒ Boolean
75 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 75 def belongs_to? = !reflection.nil? || attr.reference? |
#display_reader ⇒ Object
What the row partial prints. A belongs_to contributes the
association's label rather than its id, which is why the model gets a
delegate :name, to: :author, prefix: true โ the record and the row
projection then answer the same reader, so one partial serves both.
101 102 103 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 101 def display_reader belongs_to? ? :"#{association_name}_#{label_column}" : name end |
#filterable? ⇒ Boolean
116 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 116 def filterable? = type == :boolean |
#form_field_helper ⇒ Object
106 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 106 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.
123 124 125 126 127 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 123 def html_bounds return {} unless numeric? { min: lower_bound, max: upper_bound }.compact end |
#human_name ⇒ Object
74 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 74 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(:).
95 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 95 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.
133 134 135 136 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 133 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.
80 81 82 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 80 def name @name ||= (reflection ? reflection.foreign_key : attr.column_name).to_sym end |
#numeric? ⇒ Boolean
118 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 118 def numeric? = %i[integer decimal float].include?(type) |
#options_local ⇒ Object
105 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 105 def = :"#{association_name}_options" |
#required? ⇒ Boolean
73 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 73 def required? = @required |
#searchable? ⇒ Boolean
115 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 115 def searchable? = !belongs_to? && TEXTUAL.include?(type) |
#sortable? ⇒ Boolean
117 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 117 def sortable? = !belongs_to? && COMPARABLE.include?(type) |
#tag_event ⇒ Object
109 110 111 112 113 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 109 def tag_event return :change if belongs_to? KEYSTROKE_TYPES.include?(type) ? :input : :change end |
#tag_field_helper ⇒ Object
107 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 107 def tag_field_helper = belongs_to? ? :select_tag : TAG_HELPERS.fetch(type, :text_field_tag) |
#type ⇒ Object
72 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 72 def type = attr.type |