Models with encrypted columns can use Options now - #49
Merged
Conversation
Including the concern in a model that also uses encrypts made every save raise. Encryption registers a length validator on each encrypted column, and the validator measures the value with to_s, which an Option refuses. The validator never appears in Model.validators, only in the runtime callback chain, so the cause was invisible from the model. Skip encrypted attributes when computing the wrapped set. Applications declare encrypts after the include as often as before it, so also hook the class method and give a late-declared attribute its plain reader back.
Wrapping was all or nothing per model, so a single attribute the surrounding machinery insists on reading raw blocked the whole model from adopting the concern. errgonomic_optional_except names attributes to leave alone. It sits with delegate_optional, on every model, because it has to be callable before the include that computes the wrapped set.
The compromise list promised that a new integration exception gets a design discussion and a place on the list rather than a quiet patch; this is that entry. errgonomic_optional_except is deliberately kept off the list as configuration rather than a semantic exception.
nz
enabled auto-merge
August 11, 2026 00:21
lutzcc1
approved these changes
Aug 11, 2026
lutzcc1
left a comment
There was a problem hiding this comment.
Although practical, this Options exception seems a bit obscure.
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.
Fixes #41.
Before, a model with an encrypted column could not save at all once it used this gem: every save raised an error. That is because Rails adds its own hidden length check to encrypted columns, and that check cannot read a value inside an Option. Now encrypted columns are simply left alone, so saves work. You can also name other columns to leave alone with
errgonomic_optional_except.Detail
Model.validators(encryptable_record.rb:126-142:load_schema!→validate_column_size→validates_length_of), whosevalidate_eachcallsto_son the value — andOption#to_sraises by design.Array(encrypted_attributes)when computing the wrapped set. That alone misses the reported case, whereencryptsis declared after the include (the Set is still nil at include time), so the concern also overridesencryptsto callsuperthen un-wrap the named reader (remove_methodlets dispatch fall back to AR's attribute methods). Both declaration orders are tested.errgonomic_optional_except :attr, ..., callable before the include, as an escape hatch for whatever conflict shows up next.errgonomic_optional_exceptis deliberately kept off the list: it is configuration, not a semantic exception.Review note: the
encryptsoverride forwards Rails 8.1's(*names, **options)signature and relies onsuperreachingEncryptableRecord::ClassMethods; it is the most brittle piece of this batch and worth a close look.Tests: encrypted-column model saves, encrypted reader returns the raw value, sibling nullable column still wrapped, absent encrypted value round-trips,
errgonomic_optional_exceptskips named attributes.