Skip redundant preference re-serialization on load#6502
Closed
ikraamg wants to merge 1 commit into
Closed
Conversation
Persistable stores Preferable preferences in a YAML-serialized column. The initialize_preference_defaults callback ran on every load and reassigned the preferences attribute even when the merged defaults already matched the stored value. That assignment switches the attribute to ActiveModel's "from user" state, whose reads round-trip the hash through YAML on every access, while "from database" reads only load it. Hot paths that read calculator preferences per record paid this on every request. Shipping-rate estimation, for example, reads each shipping method's calculator preferences and re-dumped YAML once per method per estimation. Guard the assignment so it only runs when the merge actually changes the stored preferences. Unchanged records stay on the cheaper read path and defaults are still backfilled when missing.
houndci-bot
reviewed
Jun 26, 2026
|
|
||
| # NOTE: assigning preferences in after_initialize (even an identical value) flips | ||
| # the attribute to "from user" state, so every later read re-dumps YAML. Skipping | ||
| # the redundant assignment keeps reads on the cheaper "from database" path. |
There was a problem hiding this comment.
Metrics/LineLength: Line is too long. [81/80]
| loaded = PrefTest.find(@pt.id) | ||
|
|
||
| # NOTE: assigning preferences in after_initialize (even an identical value) flips | ||
| # the attribute to "from user" state, so every later read re-dumps YAML. Skipping |
There was a problem hiding this comment.
Metrics/LineLength: Line is too long. [87/80]
| it "does not re-serialize unchanged preferences when read after load" do | ||
| loaded = PrefTest.find(@pt.id) | ||
|
|
||
| # NOTE: assigning preferences in after_initialize (even an identical value) flips |
There was a problem hiding this comment.
Metrics/LineLength: Line is too long. [87/80]
| end | ||
| end | ||
|
|
||
| it "does not re-serialize unchanged preferences when read after load" do |
There was a problem hiding this comment.
Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #6502 +/- ##
=======================================
Coverage 89.68% 89.69%
=======================================
Files 993 993
Lines 20863 20864 +1
=======================================
+ Hits 18712 18713 +1
Misses 2151 2151 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
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.
Solidus stores Preferable preferences in a YAML-serialized column. The
initialize_preference_defaultscallback runs on every load and reassigns the preferences attribute even when the merged defaults already equal the stored value.That assignment flips the attribute to ActiveModel's "from user" state, whose reads round-trip the hash through YAML on every access. "from database" reads only load it, so any code that reads a freshly loaded record's preferences pays for the extra serialization.
Shipping-rate estimation is one hot path that hits this. It reads each shipping method's calculator preferences to filter by currency, so it re-serializes YAML once per shipping method, on every estimation.
This guards the assignment so it only runs when the merge actually changes the stored preferences: