| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
|
| |
`counter_cache_target` is called only when updated counter cache in
replacing target, but it was already removed at #33913.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This is a 4th attempt to make counter cache transactional completely.
Past attempts: #9236, #14849, #23357.
All existing counter cache issues (increment/decrement twice, lost
increment) are caused due to updating counter cache on the outside of
the record saving transaction by assigning belongs_to record, even
though assigning that doesn't cause the record saving.
We have the `@_after_replace_counter_called` guard condition to mitigate
double increment/decrement issues, but we can't completely prevent that
inconsistency as long as updating counter cache on the outside of the
transaction, since saving the record is not always happened after that.
We already have handling counter cache after create/update/destroy,
https://github.com/rails/rails/blob/1b90f614b1b3d06b7f02a8b9ea6cd84f15d58643/activerecord/lib/active_record/counter_cache.rb#L162-L189
https://github.com/rails/rails/blob/1b90f614b1b3d06b7f02a8b9ea6cd84f15d58643/activerecord/lib/active_record/associations/builder/belongs_to.rb#L33-L59
so just removing assigning logic on the belongs_to association makes
counter cache transactional completely.
Closes #14849.
Closes #23357.
Closes #31493.
Closes #31494.
Closes #32372.
Closes #33113.
Closes #33117
Closes #33129.
Closes #33458.
|
|
|
|
| |
same record
|
|
|
|
| |
To prevent style check in review like https://github.com/rails/rails/pull/33608#discussion_r211087605.
|
|
|
|
|
|
| |
The target object for counter cache is not always determined by the
primary key value on the model. I'd like to extract `update_couters`
onto the `Relation` for the internal use.
|
| |
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
Currently, the seen object cache is shared if join nodes have the same
target class. But it is a wrong assumption, we can't share the seen
object cache between different join nodes (e.g. `:readonly_account` and
`:accounts` have the same target class `Account`, but the instances
have the different state `readonly`).
Fixes #26805.
Closes #27737.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The "join" affix in `table_alias_for` was added 12 years ago at 02d3444
to address poor alias tracking.
`AssociationScope` no longer uses the "join" suffixed alias since
0408e21 and had been removed at a1ec8b5.
`table_alias_for` is the last place that using the useless legacy
suffixed alias, but we can't remove the suffix since some test cases
directly refers the alias name by `where` with string literal, so at
least removing the suffix would break our test cases.
(e.g. https://github.com/rails/rails/blob/b2eb1d1c55a59fee1e6c4cba7030d8ceb524267c/activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb#L699-L731).
|
|
|
|
| |
Follow up of 15367a2c674bf19eeefa12ccb64391bdd50d883d.
|
|
|
|
|
| |
Since `aliases` is a part of `JoinDependency` and already cached at
1a723c65bbe91ad969b67416233d20eff6d2a46a.
|
|
|
|
| |
It was no longer used since d7ddaa530fd1b94e22d745cbaf2e8a5a34ee9734.
|
|\
| |
| | |
Removed useless utility classes inside HABTM association builder
|
| | |
|
|/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Currently, column aliases which is used for eager loading are calculated
before constructing all table aliases in FROM clause.
`JoinDependency#join_constraints` constructs table aliases for `joins`
first, and then always re-constructs table aliases for eager loading.
If both `joins` and eager loading are given a same table association,
the re-construction would cause the discrepancy between column aliases
and table aliases.
To avoid the discrepancy, the column aliases should be calculated after
all table aliases are constructed.
Fixes #30603.
|
|
|
|
|
| |
It mark the association as loaded and this can cause the object to be in
an stale state.
|
|
|
|
|
| |
This also mark the association as loaded given we changed it in memory
and avoid the next access to the reader to make a query to the databse.
|
|\
| |
| |
| | |
Use hash lookup for deleting existing associations from `target`
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
`Array#delete` searches for all occurrences in the `target` array. When performing `dependent: :destroy` in active_record/associations/collection_association, the loop becomes O(N^2). It is particularly slow when destroying large amount of associations (e.g. 10K records).
Either `Hash` or `Set` can optimize the loop to O(N). `Hash` is slightly faster in this simple usage.
```ruby
class Dummy; end
num = 10_000
test1a = num.times.map { Dummy.new }; nil
test1b = test1a.dup
test2a = num.times.map { Dummy.new }; nil
test2b = test2a.dup
Benchmark.ips do |x|
x.config(stats: :bootstrap, confidence: 95)
x.report("hash") do
hash = test1a.group_by { |r| r }
test1b.select! { |r| !hash[r] }
end
x.report("array") do
test2a.each { |r| test2b.delete(r) }
end
x.compare!
end
```
```
Calculating -------------------------------------
hash 11.000 i/100ms
array 1.000 i/100ms
-------------------------------------------------
hash 114.586 (±16.6%) i/s - 561.000
array 1.710k (±10.3%) i/s - 8.377k
Comparison:
array: 1710.4 i/s
hash: 114.6 i/s - 14.93x slower
```
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
left_joins
This regression was caused by #30995 due to `Hash#fetch` won't invoke
default proc. Just revert the change since #30995 is completely fixed by
e9c1653.
Fixes #33048.
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
In `_create_record`, explicit `transaction` block requires rollback
handling manually when `insert_record` is failed.
We need to handle it in `_create_record`, not in `insert_record`, since
our test cases expect a record added to target and returned even if
`insert_record` is failed,
Closes #31488.
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
Rails 5.2 does not alias child joins, causing an error about duplicated table/fields:
Example:
Using some code like:
`Post.joins(:author, :categorizations).merge(Author.select(:id)).merge(Categorization.joins(:author))`
*Before this fix:*
`
SELECT ... FROM "posts" INNER JOIN "authors" ON ... INNER JOIN "authors" ON ...
`
*After this fix:*
`
SELECT ... FROM "posts" INNER JOIN "authors" ON ... INNER JOIN "authors" "authors_categorizations" ON ...
`
Before 5.2, Rails aliased the joins, but wrongfully transformed them into a LEFT OUTER JOIN.
This fix will keep them as INNER JOINS, but make sure child joins are aliased, to avoid errors.
|
| |
| |
| |
| | |
Should be done before `before_add` callbacks.
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
On belongs_to with `touch: true` association, unassigned object is
caused touching, but assigned object is not touched.
And also, if primary key is customized, it will touch against the wrong
target looked up by the customized key as primary key.
This change ensures correctly touching consistently between assigning
and unassigning.
|
| | |
|
| |
| |
| |
| | |
Since UPDATE with a subquery doesn't work on MySQL.
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
counter
If belongs_to primary key is customized, the callback will update
counters against the wrong target looked up by the customized key as
primary key.
We need to convert the customized key into an object that can be
referred to as primary key.
|
| | |
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
Since #31575, `BelongsToAssociation#target=` replaces owner record's
foreign key to fix an inverse association bug.
But the method is not only used for inverse association but also used
for eager loading/preloading, it caused some public behavior changes
(#32338, #32375).
To avoid any side-effect in loading associations, I reverted the
overriding `#target=`, then introduced `#inversed_from` to replace
foreign key in `set_inverse_instance`.
Closes #32375.
|
| |
| |
| |
| |
| | |
Originally `SingularAssociation#replace` abstract method is private, and
doesn't intend to be called directly.
|
| |
| |
| |
| | |
If a 'has one' object is created from a new record, an ActiveRecord::RecordNotSaved error is raised but this behavior was also applied to the reverse scenario.
|
| |
| |
| |
| |
| |
| |
| | |
Currently `ids_reader` doesn't respect dirty target when the target is
not loaded yet unlike `collection.size`. I believe the inconsistency is
a bug, fixes the `ids_reader` to behave consistently regardless of
whether target is loaded or not.
|
| |
| |
| |
| |
| |
| |
| | |
Already loaded associations were running an extra query when `size` was called on the association.
This fix ensures that an extra query is no longer run.
Update tests to use proper methods
|
|\ \
| | |
| | |
| | |
| | | |
samdec/multiple-has-one-through-associations-build-bug
Fix .new with multiple through associations
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | | |
This fixes a bug with building an object that has multiple
`has_many :through` associations through the same object.
Previously, when building the object via .new, the intermediate
object would be created instead of just being built.
Here's an example:
Given a GameBoard, that has_one Owner and Collection through Game.
The following line would cause a game object to be created in the
database.
GameBoard.new(owner: some_owner, collection: some_collection)
Whereas, if passing only one of those associations into `.new` would
cause the Game object to be built and not created in the database.
Now the above code will only build the Game object, and not save it.
|
| | |
| | |
| | |
| | |
| | | |
So `target.is_a?(Array)` is meaningless, and just use `target.empty?`
instead of `target.blank?`.
|
|/ / |
|
| |
| |
| |
| |
| |
| |
| |
| |
| | |
When a belongs to association's target is set, its foreign key is now
updated to match the new target. This is the correct behaviour when a
new record is assigned, but not when the existing record is preloaded.
As long as we mark the association as loaded, we can skip setting the
target when the record is missing and avoid clobbering the foreign key.
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
When a class has a belongs_to or has_one relationship with dependent: :destroy
option enabled, objects of this class should not be deleted if it's dependents
cannot be deleted.
Example:
class Parent
has_one :child, dependent: :destroy
end
class Child
belongs_to :parent, inverse_of: :child
before_destroy { throw :abort }
end
c = Child.create
p = Parent.create(child: c)
p.destroy
p.destroyed? # expected: false; actual: true;
Fixes #32022
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
This reverts ignoring polymorphic error introduced at 02da8ae.
What the ignoring want to solve was caused by force eager loading
regardless of whether it is necessary, but it has been fixed by #29043.
The ignoring is now only causing a mismatch of `exists?` behavior with
`to_a`, `count`, etc. It should behave consistently.
|
| |
| |
| |
| |
| |
| |
| | |
This is an alternative of #29722, and follow up of #32048.
This does not change the current behavior, but makes it easier to modify
all polymorphic names consistently.
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
This comment was added at 070dda2. That arguments has already been
changed since those are internal nodoc classes, but the comment does not
reflect the current state.
I decided to remove the staled comment since it is not useful for
understanding what the class does.
[ci skip]
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
This is an alternative of #29722, and revert of #29601 and a1fcbd9.
Currently, association creation and normal association finding doesn't
respect `store_full_sti_class`. But eager loading and preloading respect
the setting. This means that if set `store_full_sti_class = false`
(`true` by default), eager loading and preloading can not find
created polymorphic records.
Association creation and finding should work consistently.
|
| |
| |
| |
| |
| | |
Since #32028, Rails 6 requires Ruby 2.3+.
No longer needed workaround for Ruby 2.2 "private attribute?" warning.
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
3acc5d6 was changed the order of scope evaluation from through scope to
the association's own scope to be prioritized over the through scope.
But the sorting order will be prioritized that is evaluated first. It is
unintentional effect, association scope's sorting order should be
prioritized as well.
Fixes #32008.
|
| | |
|
| | |
|
| |
| |
| |
| |
| |
| |
| |
| | |
This reverts commit 487a1061cc496455dfe5ee84d1e49d509c1675b5.
This `#--` is necessary for the doc of `distinct`.
[ci skip]
|
| | |
|
| |
| |
| |
| |
| |
| |
| | |
With #31615 `type_for_attribute` accepts either
a symbol as well as a string. `has_attribute?` and `attribute_alias`
also accept either. Since these methods call `to_s` on the argument,
we no longer need to do that at the call site.
|