Class: Hibiki::Rails::Generators::ModelIntrospection
- Inherits:
-
Object
- Object
- Hibiki::Rails::Generators::ModelIntrospection
- Defined in:
- lib/generators/hibiki/rails/scaffold_schema.rb
Overview
Reads a live ActiveRecord model into ScaffoldColumns.
Its own class because introspection is the path with real steps — ignoring the framework's own columns, pairing foreign keys back to their reflections, resolving a label column through the association, and reading validators. The attribute path is a one-line map by comparison, which is why only this half is worth naming.
Constant Summary collapse
- LABEL_CANDIDATES =
What a belongs_to's label column is likely to be called, in preference order. Only reachable on this path: no argument list can state what column of another table a select should display.
%w[name title label email].freeze
Instance Method Summary collapse
-
#column_for(attr) ⇒ Object
The introspected column an argument names, or nil when the model has no such column.
- #columns ⇒ Object
-
#initialize(model) ⇒ ModelIntrospection
constructor
A new instance of ModelIntrospection.
-
#polymorphic?(attr) ⇒ Boolean
A polymorphic belongs_to is refused whether the ARGUMENT says so (
imageable:references{polymorphic}) or only the model does. - #skipped ⇒ Object
- #timestamps? ⇒ Boolean
-
#unmirrored_unique_indexes(names) ⇒ Object
Unique indexes the model does not mirror with a validator of its own, as column-name lists.
Constructor Details
#initialize(model) ⇒ ModelIntrospection
Returns a new instance of ModelIntrospection.
212 213 214 215 216 217 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 212 def initialize(model) @model = model belongs_tos = model.reflect_on_all_associations(:belongs_to) @polymorphic = belongs_tos.select(&:polymorphic?) @by_foreign_key = (belongs_tos - @polymorphic).index_by { it.foreign_key.to_s } end |
Instance Method Details
#column_for(attr) ⇒ Object
The introspected column an argument names, or nil when the model has no such column.
A reference is matched by its ASSOCIATION name first, because that is
how a belongs_to is declared (author:references, never
author_id:references) and because belongs_to :author, foreign_key: :writer_id is precisely the case where the association and its
column disagree — the argument can only name the association, and
only the reflection knows the column.
270 271 272 273 274 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 270 def column_for(attr) return by_association[attr.name.to_sym] || by_name[attr.column_name.to_sym] if attr.reference? by_name[attr.column_name.to_sym] end |
#columns ⇒ Object
219 220 221 222 223 224 225 226 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 219 def columns @columns ||= @model.columns_hash.each_value.filter_map do |column| next if ignored.include?(column.name) reflection = @by_foreign_key[column.name] reflection ? reference_column(reflection) : scalar_column(column) end end |
#polymorphic?(attr) ⇒ Boolean
A polymorphic belongs_to is refused whether the ARGUMENT says so
(imageable:references{polymorphic}) or only the model does. Without
this the plain imageable:references spelling would match nothing —
both its columns are ignored — and fall through to the argument's own
answer, emitting a collection_select over a table that does not
exist.
282 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 282 def polymorphic?(attr) = @polymorphic.any? { it.name.to_s == attr.name } |
#skipped ⇒ Object
228 229 230 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 228 def skipped @polymorphic.map { [it.name.to_s, ScaffoldSchema::REFUSALS[:polymorphic?]] } end |
#timestamps? ⇒ Boolean
232 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 232 def = @model.columns_hash.key?("created_at") |
#unmirrored_unique_indexes(names) ⇒ Object
Unique indexes the model does not mirror with a validator of its own, as column-name lists.
A database constraint is not a validator, and ReactiveForm#commit can only mirror what the model checks — so a duplicate raises RecordNotUnique instead of returning false, which on the graph thread is a dev-log line and a form that quietly saves nothing.
Restricted to indexes at least one of whose columns this form actually writes: an index nothing here can violate is not this generator's business.
A CONDITIONAL uniqueness validator counts as mirrored, unlike
everywhere else in this class. Elsewhere the question is "can this be
checked before a round trip", where a condition the form cannot
evaluate disqualifies it; here it is "does the model know about this
constraint at all", and a deliberate if: is an answer.
251 252 253 254 255 256 257 258 259 |
# File 'lib/generators/hibiki/rails/scaffold_schema.rb', line 251 def unmirrored_unique_indexes(names) @model.connection.indexes(@model.table_name) .select { unmirrored?(it, names) } .map { it.columns.map(&:to_sym) } rescue StandardError # Introspecting indexes is the one thing here that needs more than # the schema cache. A generator must not fail over a notice. [] end |