@@ -686,8 +686,8 @@ def create_accessors(name, meth, options = {})
686686 def create_field_getter ( name , meth , field )
687687 generated_methods . module_eval do
688688 re_define_method ( meth ) do
689+ # Handle lazy defaults first (before reading raw value)
689690 raw = read_raw_attribute ( name )
690- # Handle lazy defaults outside of cache to avoid recursive locking
691691 if lazy_settable? ( field , raw )
692692 write_attribute ( name , field . eval_default ( self ) )
693693 # Don't cache localized fields as they depend on I18n.locale
@@ -698,9 +698,10 @@ def create_field_getter(name, meth, field)
698698 # Atomically fetch or compute the cached value
699699 # Cache stores [raw_value, demongoized_value] to detect stale cache
700700 value = @__demongoized_cache . compute_if_absent ( name ) do
701- # Cache miss - compute and store
702- demongoized = process_raw_attribute ( name . to_s , raw , field )
703- [ raw , demongoized ]
701+ # Cache miss - re-read raw inside block to avoid race conditions
702+ current_raw = read_raw_attribute ( name )
703+ demongoized = process_raw_attribute ( name . to_s , current_raw , field )
704+ [ current_raw , demongoized ]
704705 end
705706
706707 # Check if cached raw value matches current raw value
0 commit comments