Skip to content

Skip redundant preference re-serialization on load#6502

Closed
ikraamg wants to merge 1 commit into
solidusio:mainfrom
ikraamg:skip-redundant-preference-serialization
Closed

Skip redundant preference re-serialization on load#6502
ikraamg wants to merge 1 commit into
solidusio:mainfrom
ikraamg:skip-redundant-preference-serialization

Conversation

@ikraamg

@ikraamg ikraamg commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Solidus stores Preferable preferences in a YAML-serialized column. The initialize_preference_defaults callback 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:

  • unchanged records stay on the cheaper read path
  • defaults are still backfilled when they are missing
  • behaviour is otherwise the same

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.

# 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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Metrics/LineLength: Line is too long. [87/80]

end
end

it "does not re-serialize unchanged preferences when read after load" do

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.

@github-actions github-actions Bot added the changelog:solidus_core Changes to the solidus_core gem label Jun 26, 2026
@codecov

codecov Bot commented Jun 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.69%. Comparing base (8d781ac) to head (7145697).

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.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ikraamg ikraamg closed this Jun 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog:solidus_core Changes to the solidus_core gem

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants