Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not consolidate persisted in-memory records #43517

Merged
merged 1 commit into from Nov 25, 2021

Conversation

hovsater
Copy link
Contributor

@hovsater hovsater commented Oct 24, 2021

Summary

merge_target_lists is called with two arguments. A collection of
persisted records and a collection of in-memory records. If the
in-memory collection contains any persisted records we can safely
reject them as the persisted collection is already up-to-date.

Fixes #43516.

@ghiculescu
Copy link
Member

ghiculescu commented Oct 24, 2021

Could you add a test and a changelog entry?

@hovsater
Copy link
Contributor Author

@ghiculescu sure thing!

@hovsater
Copy link
Contributor Author

@ghiculescu I've now added a test and a changelog entry as requested. 🙂

Comment on lines +293 to +301
def test_target_merging_ignores_persisted_in_memory_records
david = authors(:david)
assert david.thinking_posts.include?(posts(:thinking))

david.thinking_posts.create!(title: "Something else entirely", body: "Does not matter.")

assert_equal 1, david.thinking_posts.size
assert_equal 1, david.thinking_posts.to_a.size
end
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
def test_target_merging_ignores_persisted_in_memory_records
david = authors(:david)
assert david.thinking_posts.include?(posts(:thinking))
david.thinking_posts.create!(title: "Something else entirely", body: "Does not matter.")
assert_equal 1, david.thinking_posts.size
assert_equal 1, david.thinking_posts.to_a.size
end
def test_target_merging_ignores_persisted_in_memory_records
david = authors(:david)
assert david.thinking_posts.include?(posts(:thinking))
david.thinking_posts.create!(title: "Something else entirely", body: "Does not matter.")
assert_equal 1, david.thinking_posts.size
assert_equal 1, david.thinking_posts.to_a.size
end
def test_target_merging_does_not_ignores_persisted_in_memory_records_that_match_scope
david = authors(:david)
assert david.thinking_posts.include?(posts(:thinking))
david.thinking_posts.create!(title: "So I was thinking", body: "This should be included in the scope.")
assert_equal 2, david.thinking_posts.size
assert_equal 2, david.thinking_posts.to_a.size
end

Does this also work? (Mostly just want to make sure I've understood the issue correctly.)

Copy link
Contributor Author

@hovsater hovsater Oct 26, 2021

Choose a reason for hiding this comment

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

Yes, correct. That test case would pass as well. 🙂

Copy link
Member

Choose a reason for hiding this comment

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

Is it worth adding it as an additional test?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think so. That behaviour was already present prior to my change, so I would expect things to blow up left and right if that part broke. But if anyone feel strongly about it, I don't mind adding another test case.

@ghiculescu ghiculescu added the ready PRs ready to merge label Oct 25, 2021
@@ -335,7 +335,7 @@ def merge_target_lists(persisted, memory)
end
end

persisted + memory
persisted + memory.reject(&:persisted?)
Copy link
Member

Choose a reason for hiding this comment

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

If the issue is that persisted and memory have the same objects, is this a better fix?

Suggested change
persisted + memory.reject(&:persisted?)
[persisted + memory].flatten.uniq

Choose a reason for hiding this comment

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

why don't just do

(persisted + memory).uniq

Copy link
Member

Choose a reason for hiding this comment

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

🤦 yeah that

Copy link
Contributor Author

@hovsater hovsater Oct 26, 2021

Choose a reason for hiding this comment

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

The issue isn't that persisted and memory contains the same records. In fact, that is to be expected. merge_target_lists already handles duplicates. The issue is that the memory collection may contain persisted records that are not present in the persisted collection. These records are currently being included even though they shouldn't. The persisted collection is already up-to-date, so if there are records in memory that are persisted but not part of persisted they are invalid (e.g., violating the association scope).

Choose a reason for hiding this comment

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

@kevinsjoberg I think the documentation at the beginning of this method should also be updated to reflect this change.

@tiendo1011
Copy link

@kevinsjoberg I feel like the root cause is the record being added to memory without respecting the association condition. Do you think it makes more sense if we fix it at the moment it tries to add the record to memory?

I think it's this line:

@hovsater
Copy link
Contributor Author

hovsater commented Oct 26, 2021

@kevinsjoberg I feel like the root cause is the record being added to memory without respecting the association condition. Do you think it makes more sense if we fix it at the moment it tries to add the record to memory?

I think it's this line:

I was thinking the same thing initially but came to the conclusion that it can't be fixed at that point. I might be wrong here, but to my understanding scopes are not enforced at that level.

`merge_target_lists` is called with two arguments. A collection of
persisted records and a collection of in-memory records. If the
in-memory collection contains any persisted records we can safely
reject them as the `persisted` collection is already up-to-date.
@hovsater
Copy link
Contributor Author

hovsater commented Nov 3, 2021

I've rebased with latest main.

@rafaelfranca rafaelfranca merged commit 060ae8c into rails:main Nov 25, 2021
rafaelfranca added a commit that referenced this pull request Nov 25, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
activerecord ready PRs ready to merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Consolidation between persisted and in-memory records are broken for scoped associations
5 participants