Fix enum-backed integer columns annotations - #380
Open
dmke wants to merge 2 commits into
Open
Conversation
## Summary
Restore enum-backed defaults in annotations: `default("idnow")` instead
of the raw `default(0)` emitted since v4.24.0. Fixes drwl#373.
## Motivation
drwl#358 detects `attribute :foo, default: X` overrides by comparing
`Model#column_defaults[name]` against `column.default` deserialized
through the schema-level cast type. That comparison casts the same raw
default through two different type systems, so any decorated attribute
type looks like an override: an enum casts the DB default `0` into its
label, the schema type casts it into `0`, the values differ, and the
schema value wins. Enum columns are the visible case, but every
decorated type is affected.
## Changes
Compare the raw, pre-cast values instead. Rails builds default
attributes with `Attribute.from_database(column.name, column.default,
type)`, so `_default_attributes[name].value_before_type_cast` is
`column.default` itself unless `attribute :foo, default: X` replaced it
with a `UserProvidedDefault`. Type decoration goes through `with_type`,
which preserves the raw value. No casting involved, so the check is
exact for both cases.
The test doubles gain `_default_attributes` to mirror that structure.
## Summary
Make the default shown for enum backed columns configurable, via
`enum_default_format` or `--enum-default-format`:
default("idnow") # label (default)
default(0) # raw
default(0: "idnow") # both
`label` keeps the historical output. Relates to drwl#373.
## Motivation
The label is the meaningful value for most readers, but it hides the
integer that is actually stored, which matters when reading queries or
raw data. Neither representation is right for everyone, so let the user
pick.
## Changes
`ModelWrapper#column_defaults` knows both values already: the label from
`Model#column_defaults` and the raw one from the schema cast type. It
now picks between them for columns listed in `defined_enums`.
The `both` format needs to carry two values down to the annotation, so
it passes an `EnumDefault` struct that `DefaultValueBuilder` renders by
quoting each half. Going through `Hash#inspect` instead would make the
output depend on the Ruby version.
String backed enums fall through to the label in every format, since
their raw value is the label.
georgebancila
approved these changes
Aug 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR contains two changes, feel free to omit the latter if not desired.
Part 1: Detect attribute default overrides by raw value
Restores enum-backed defaults in annotations. Reverts to
default("idnow")instead of the rawdefault(0)emitted since v4.24.0.Fixes #373.
Part 2: Add
enum_default_formatoptionMake the default shown for enum-backed columns configurable, via
enum_default_formator--enum-default-format:labelkeeps the historical output.