Stop relying on the private validation_context= writer - #770
hikmetba-bit wants to merge 1 commit into
Conversation
sane_ancestor_ids? saved/nulled/restored self.validation_context around a direct call to each column validator's #validate_each. Rails main removed the private validation_context= writer entirely (rails/rails#58220) since ActiveModel::Validations#valid? now sets the context on an internal ValidationContext object instead, so this call raises NoMethodError on current Rails main, breaking any move of a node with descendants and check_ancestry_integrity!. The save/restore was unnecessary in the first place: validate_each is called directly here, bypassing the normal valid?/run_validations! pipeline that consults validation_context, so nulling and restoring it around the call had no effect on which validators ran. Drop it. Fixes stefankroes#766.
|
@hikmetba-bit so we are using this to detect if we introduced an error or if there was an error from the model. (some people save records to the database with errors in them - which happens when you modify your validations and don't revalidate every record in the database) So this concept is necessary in general Maybe there is a better way for us to validate that we properly updated the ancestry with a custom validator or calling the validator directly? Need to look into how rails suggests running a subset of validators. I think this concept is still necessary to rails in general, so it may be as simple as tracking down how this changed. |
Summary
Fixes #766.
sane_ancestor_ids?saved, nulled, and restoredself.validation_contextaround a direct call to each column validator's#validate_each. Rails main removed the privatevalidation_context=writer entirely (rails/rails#58220), sinceActiveModel::Validations#valid?now sets the context on an internalValidationContextobject instead. The removed writer breakssane_ancestor_ids?on current Rails main with:which in turn breaks moving a node that has descendants and
check_ancestry_integrity!(both call this method), exactly as described in the issue (credit to the reporter for the excellent diagnosis, down to the exact Rails PR and line number).Fix
This is Option 1 from the issue: the save/restore was unnecessary to begin with.
validate_eachis called directly on each validator here, bypassing the normalvalid?/run_validations!pipeline that actually readsvalidation_context— so nulling and restoring it around this direct call never affected which validators ran or how. Dropped both the write and theensurerestore.Test
Added
test_sane_ancestor_ids_does_not_rely_on_validation_context_writertointegrity_checking_and_restoration_test.rb: it stubsvalidation_context=on a single instance to raiseNoMethodError(simulating the writer's removal on Rails main) and confirmssane_ancestor_ids?still runs to completion. Mutation-tested: reverting the source change makes it fail with that exactNoMethodErrorthroughsane_ancestor_ids?; with the fix, the fullintegrity_checking_and_restoration_test.rbfile passes (4/4). Ran the full suite (SKIP_NATIVE_DB_GEMS=1 bundle exec rake test— trilogy/pg require native client libs not available in this sandbox, so I tested against the default SQLite adapter only): 259 runs, same 5 pre-existingSortByAncestryTestfailures with or without this change (confirmed by reverting and re-running - those failures are SQLite ordering-related and unrelated to this fix), no new failures.🤖 Generated with Claude Code