Skip to content

Title: 2.3.0 drops in-place nested session writes (changed? misses mutations) #236

Description

@yaakov-sanders

Summary

2.3.0's #166 optimization makes write_session skip the save when record.changed? is false — but Session#data= can't detect
in-place mutation, so nested session writes are silently dropped. 2.2.0 always saved, so this worked.

Cause

#active_record_store.rb (2.3.0)

record.data = session_data
return sid unless record.changed? || record.new_record?   # new

#session.rb

def data=(data)
  attribute_will_change!(@@data_column_name) if data != self.data
  @data = data
end

get_session hands Rack the record's own @data object. When an app mutates a nested value in place (session[:foo][k] << v), the
change bleeds into @data, so at write time session_data deep-equals self.data, changed? is false, and the save is skipped.

Repro

record = ActiveRecord::SessionStore::Session.find_by_session_id("abc")
data = record.data          # {"key" => ["a"]}
data["key"] << "b"       # in-place
record.data = data
record.changed?             # => false on 2.3.0; save is skipped

Suggested fix

Snapshot the deserialized data (deep copy) at read time and diff against that at write, instead of comparing against the
already-mutated @data.

Env: 2.3.0 (regression vs 2.2.0), Rails 8.1, :active_record_store

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions