Skip to content

fix: Remove ActiveRecord::Dirty to preserve nested document changes on save#12

Merged
pimpin merged 15 commits intomasterfrom
fix_save_return_for_nested
Dec 1, 2025
Merged

fix: Remove ActiveRecord::Dirty to preserve nested document changes on save#12
pimpin merged 15 commits intomasterfrom
fix_save_return_for_nested

Conversation

@pimpin
Copy link
Collaborator

@pimpin pimpin commented Jan 8, 2025

Problem

When modifying nested documents and calling save(), changes were incorrectly reset, causing data loss. This happened because ActiveRecord::Dirty's changes_applied callback cleared attribute changes prematurely.

Reproduction:

obj.others[0].name = "foo"
obj.others[1].child = SubTypeTest.new(name: "baz")
obj.save!

# BUG: Nested changes were lost! ❌
obj.others[0].name  # => nil (expected: "foo")
obj.others[1].child # => nil (expected: SubTypeTest)

Solution

Remove dependency on ActiveRecord::Dirty and implement custom change tracking that properly handles nested documents.

What changed:

  1. Removed ActiveRecord::Dirty inclusion from Document base class
  2. Disabled super call in changes_applied to prevent premature change clearing
  3. Added proper type casting at assignment time to match ActiveRecord behavior:
    # Cast → Serialize → Cast cycle ensures consistent nested object handling
    casted_value = type.cast(type.serialize(type.cast(new_attribute_value)))
  4. Preserved change tracking API (changed?, changes, etc.) through custom implementation

Benefits:

  • ✅ Nested document changes persist correctly after save
  • ✅ Type casting happens at assignment time (consistent with AR)
  • ✅ Maintains backward compatibility with change tracking API
  • ✅ Reduces dependency footprint

Testing

Breaking Changes

⚠️ This PR removes ActiveRecord::Dirty as a dependency.

Impact Analysis:

  • Low risk: The public change tracking API (changed?, changes, changed_attributes, etc.) remains functional through custom implementation
  • Potential issue: Code that explicitly relies on ActiveRecord::Dirty-specific internals (private methods, modules) may break
  • Mitigation: Most applications use only the standard change tracking API which continues to work

Recommendation: Review your codebase for any direct usage of ActiveRecord::Dirty internals before upgrading.

Checklist

  • CI is green
  • Regression tests added
  • Tested in large production application

Related

pimpin added 6 commits January 6, 2025 15:33
NB : in AR, the cast is done at assignment time. Lets try to do it.
TODO : fix move casting stuff from serialize and place them in cast obviously
@pimpin pimpin changed the title Remove ActiveRecord::Dirty Remove ActiveRecord::Dirty usage Jan 8, 2025
And keep unchanged the serialize_value needed for queries (ie find_by_some_time)
@pimpin pimpin force-pushed the fix_save_return_for_nested branch from f4ae61b to 3d71024 Compare January 16, 2025 15:46
@pimpin pimpin requested a review from Copilot June 23, 2025 15:27

This comment was marked as outdated.

pimpin and others added 3 commits June 24, 2025 17:34
- Remove double casting in create_setters to avoid type inconsistencies
- Fix Timestamp type precision by applying floor() during cast
- Fix DateTimeWith3Decimal precision handling in both cast and serialize

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@pimpin pimpin marked this pull request as ready for review August 25, 2025 15:56
@pimpin
Copy link
Collaborator Author

pimpin commented Aug 25, 2025

Thanks to Claude, we get a green inplem according to CI. Let's check in Docto CI that this implem is not breaking smth.

@pimpin pimpin requested a review from Copilot August 25, 2025 16:15
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR removes ActiveRecord::Dirty usage to fix a bug where nested resource changes were being reset on save operations. The change replaces the ActiveRecord::Dirty dependency with a custom implementation to handle change tracking properly for nested resources.

  • Removes ActiveModel::Dirty inclusion and replaces with custom Changeable module
  • Modifies changes_applied method to prevent unwanted change resets
  • Adds test coverage for the nested resource change preservation bug

Reviewed Changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
lib/couchbase-orm/base.rb Removes ActiveModel::Dirty inclusion, keeping only custom Changeable module
lib/couchbase-orm/changeable.rb Removes call to super in changes_applied to prevent change resets
lib/couchbase-orm/types/timestamp.rb Adds .floor calls to timestamp casting for consistency
spec/type_spec.rb Adds cast method to DateTimeWith3Decimal test class
spec/type_nested_spec.rb Adds test cases to verify nested resource changes are preserved after save

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@pimpin pimpin marked this pull request as draft August 26, 2025 14:08
@pimpin pimpin changed the title Remove ActiveRecord::Dirty usage fix: Remove ActiveRecord::Dirty to preserve nested document changes on save Nov 25, 2025
@pimpin pimpin marked this pull request as ready for review November 25, 2025 16:44
@pimpin pimpin merged commit f37a768 into master Dec 1, 2025
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants