Skip to content

Map class names back to integers in _write_attribute (Rails 7.1+ has_many reload) - #70

Open
Mohith26 wants to merge 1 commit into
clio:masterfrom
Mohith26:fix/merge-target-lists-write-attribute
Open

Mohith26 wants to merge 1 commit into
clio:masterfrom
Mohith26:fix/merge-target-lists-write-attribute

Conversation

@Mohith26

@Mohith26 Mohith26 commented Nov 3, 2026

Copy link
Copy Markdown

Fixes #69.

On Rails 7.1+, CollectionAssociation#merge_target_lists copies reloaded rows onto records the caller already holds with mem_record._write_attribute(name, record[name]). For polymorphic integer type columns the gem's [] returns the mapped class name, and _write_attribute skips the gem's []=, so the string goes straight into the integer column and is cast to 0. The database row is fine, but the in-memory record now points at whatever type is mapped to 0 (or nothing).

This adds a _write_attribute override next to [] / []=: when the attribute is one of the model's polymorphic foreign types and the value is a String, it's mapped back through <foreign_type>_mapping before calling super. Integer values (what the generated setters pass) are untouched, and an unknown string falls through unchanged.

Tests:

  • New spec "When a has_many reload merges into records the caller still holds" builds two links through cat.source_links.new(target: ...), saves them, triggers the reload with .length, and checks the held records keep target_type 2 / "Drink". It fails on master (got: 0) and passes with the fix.
  • bundle exec rspec: 43 examples, 0 failures on ActiveRecord 8.1.4 and on 7.2.4 (Ruby 4.0.6 locally).
  • The reproduction script from the issue prints FAIL on master and PASS with this change, on both 8.1.4 and 7.2.4.

I didn't run the 7.0 gemfile locally; that version doesn't go through _write_attribute in merge_target_lists, so the override should be a no-op there. Added a CHANGELOG entry under Unreleased and left the version alone.

Rails 7.1+ CollectionAssociation#merge_target_lists copies reloaded values
onto in-memory records with _write_attribute(name, record[name]). The
gem's [] returns the mapped class name for polymorphic integer type
columns, so the integer column ended up cast to 0 and the in-memory record
pointed at the wrong type. Fixes clio#69.
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.

has_many association does not work with Rails 7.1+

1 participant