aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/associations
Commit message (Collapse)AuthorAgeFilesLines
* Ensure `StatementCache#execute` never raises `RangeError`Ryuta Kamizono2019-01-182-5/+1
| | | | | | | | | | | | | Since 31ffbf8d, finder methods no longer raise `RangeError`. So `StatementCache#execute` is the only place to raise the exception for finder queries. `StatementCache` is used for simple equality queries in the codebase. This means that if `StatementCache#execute` raises `RangeError`, the result could always be regarded as empty. So `StatementCache#execute` just return nil in that range error case, and treat that as empty in the caller side, then we can avoid catching the exception in much places.
* Refs #28025 nullify *_type column on polymorphic associations on :nu… ↵Laerti2019-01-153-2/+9
| | | | | | (#28078) This PR addresses the issue described in #28025. On `dependent: :nullify` strategy only the foreign key of the relation is nullified. However on polymorphic associations the `*_type` column is not nullified leaving the record with a NULL `*_id` but the `*_type` column is present.
* Merge pull request #34806 from bogdan/reuse-find-targetRyuta Kamizono2018-12-274-30/+20
|\ | | | | | | Reuse AR::Association#find_target method
| * Reuse AR::Association#find_target methodBogdan Gusiev2018-12-274-29/+21
| |
* | Merge pull request #34609 from kamipo/delete_all_on_collection_proxyRyuta Kamizono2018-12-042-0/+3
|\ \ | | | | | | | | | Ensure that `delete_all` on collection proxy returns affected count
| * | Ensure that `delete_all` on collection proxy returns affected countRyuta Kamizono2018-12-042-0/+3
| |/ | | | | | | | | | | | | Unlike the `Relation#delete_all`, `delete_all` on collection proxy doesn't return affected count. Since the `CollectionProxy` is a subclass of the `Relation`, this inconsistency is probably not intended, so it should return the count consistently.
* / Reset scope after collection deleteGannon McGibbon2018-12-041-4/+4
|/ | | | | Reset scope after delete on collection association to clear stale offsets of removed records.
* Revert "Merge pull request #34538 from bogdan/reuse-find-target"Ryuta Kamizono2018-11-283-23/+28
| | | | | | | This reverts commit f2ab8b64d4d46d7199f94c3e21021f414a4d259a, reversing changes made to b9c7305dbe57931a153a540d49ae5d469af61a14. Reason: `scope.take` is not the same with `scope.to_a.first`.
* Reuse code in AR::Association#find_targetBogdan Gusiev2018-11-273-29/+23
| | | | | | | Before this patch, singular and collection associations had different implementations of the #find_target method. This patch reuses the code properly through extending the low level methods.
* Optimize difference and intersectionFlorian Ebeling2018-11-061-17/+9
|
* Rename union to intersectionFlorian Ebeling2018-11-063-3/+3
|
* Fix handling of duplicates for `replace` on has_many-throughFlorian Ebeling2018-11-063-3/+41
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | There was a bug in the handling of duplicates when assigning (replacing) associated records, which made the result dependent on whether a given record was associated already before being assigned anew. E.g. post.people = [person, person] post.people.count # => 2 while post.people = [person] post.people = [person, person] post.people.count # => 1 This change adds a test to provoke the former incorrect behavior, and fixes it. Cause of the bug was the handling of record collections as sets, and using `-` (difference) and `&` (union) operations on them indiscriminately. This temporary conversion to sets would eliminate duplicates. The fix is to decorate record collections for these operations, and only for the `has_many :through` case. It is done by counting occurrences, and use the record together with the occurrence number as element, in order to make them work well in sets. Given a, b = *Person.all then the collection used for finding the difference or union of records would be internally changed from [a, b, a] to [[a, 1], [b, 1], [a, 2]] for these operations. So a first occurrence and a second occurrence would be distinguishable, which is all that is necessary for this task. Fixes #33942.
* Don't expose internal `get_value`/`set_value` methodsRyuta Kamizono2018-10-181-1/+1
|
* Merge pull request #34094 from ↵Ryuta Kamizono2018-10-103-3/+5
|\ | | | | | | | | christophemaximin/fix-activerecord-clearing-of-query-cache Fix inconsistent behavior by clearing QueryCache when reloading associations
| * Clear QueryCache when reloading associationsChristophe Maximin2018-10-103-3/+5
| |
* | Don't expose internal methods in the associationsRyuta Kamizono2018-10-082-32/+32
| |
* | Fix `AssociationRelation` not to set inverse instance key just like beforeRyuta Kamizono2018-10-071-0/+8
|/ | | | | | | | | | | | | | | | | Since #31575, `set_inverse_instance` replaces the foreign key by the current owner immediately to make it happen when a record is added to collection association. But `set_inverse_instance` is not only called when a record is added, but also when a record is loaded from queries. And also, that loaded records are not always associated records for some reason (using `or`, `unscope`, `rewhere`, etc). It is hard to distinguish whether or not we should invoke `set_inverse_instance`, but at least we should avoid the undesired side-effect which was brought from #31575. Fixes #34108.
* Restore `preloaders_for_one` methodRyuta Kamizono2018-10-051-5/+9
| | | | Since the above comment is for the `preloaders_for_one`.
* Merge pull request #33938 from faucct/bugfix/preload_through_no_recordsEileen M. Uchitelle2018-10-041-28/+24
|\ | | | | ActiveRecord::Associations::Preloader should not fail to preload through missing records
| * ActiveRecord::Associations::Preloader should not fail to preload through ↵Nikita Sokolov2018-10-021-28/+24
| | | | | | | | missing records
* | Fix call sitesGannon McGibbon2018-10-021-1/+1
|/
* Add `Style/RedundantFreeze` to remove redudant `.freeze`Yasuo Honda2018-09-291-1/+1
| | | | | | | | | | | | | | | | | | | | | Since Rails 6.0 will support Ruby 2.4.1 or higher `# frozen_string_literal: true` magic comment is enough to make string object frozen. This magic comment is enabled by `Style/FrozenStringLiteralComment` cop. * Exclude these files not to auto correct false positive `Regexp#freeze` - 'actionpack/lib/action_dispatch/journey/router/utils.rb' - 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb' It has been fixed by https://github.com/rubocop-hq/rubocop/pull/6333 Once the newer version of RuboCop released and available at Code Climate these exclude entries should be removed. * Replace `String#freeze` with `String#-@` manually if explicit frozen string objects are required - 'actionpack/test/controller/test_case_test.rb' - 'activemodel/test/cases/type/string_test.rb' - 'activesupport/lib/active_support/core_ext/string/strip.rb' - 'activesupport/test/core_ext/string_ext_test.rb' - 'railties/test/generators/actions_test.rb'
* Avoid extra touch queries when counter cache is updatedRyuta Kamizono2018-09-271-2/+8
| | | | Since counter cache handles touch option too.
* Refactor counter cache to extract `decrement_counters_before_last_save` on ↵Ryuta Kamizono2018-09-272-48/+31
| | | | the belongs_to association
* Merge pull request #31819 from bpohoriletz/masterEileen M. Uchitelle2018-09-261-4/+3
|\ | | | | If association is a hash-like object preloading fails
| * If association is a hash-like object preloading failsBohdan Pohorilets2018-09-261-4/+3
| | | | | | | | | | | | If you pass a hash-like object to preload associations (for example ActionController::Parameters) preloader will fail with the ArgumentError. This change allows passing objects that may be converted to a Hash or String into a preloader
* | Revert "Remove `counter_cache_target` which is no longer called"Ryuta Kamizono2018-09-261-1/+10
| | | | | | | | | | | | | | | | This reverts commit 376ffe0ea2e59dc51461122210729c05a10fb443. Since 38fae1f, `association.increment_counters` is called without inflated parent target if inverse_of is disabled. In that case, that commit would cause extra queries to inflate parent.
* | Update counter cache in memory if parent target is existedRyuta Kamizono2018-09-261-10/+3
|/ | | | Fixes #19550.
* Remove `counter_cache_target` which is no longer calledRyuta Kamizono2018-09-261-10/+1
| | | | | `counter_cache_target` is called only when updated counter cache in replacing target, but it was already removed at #33913.
* Don't update counter cache unless the record is actually savedRyuta Kamizono2018-09-193-23/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* ActiveRecord::Associations::Preloader should preload all instances of the ↵Nikita Sokolov2018-09-161-1/+0
| | | | same record
* Enable Style/ParenthesesAroundCondition copRyuta Kamizono2018-08-191-1/+1
| | | | To prevent style check in review like https://github.com/rails/rails/pull/33608#discussion_r211087605.
* Extract `Relation#update_counters` for internal useRyuta Kamizono2018-07-302-13/+8
| | | | | | 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.
* Avoid unneeded expanded column aliases array cachingRyuta Kamizono2018-07-102-8/+5
|
* Don't extract `readonly_value` each timeRyuta Kamizono2018-07-032-5/+7
|
* Don't share seen object cache between different join nodes in eager loadingRyuta Kamizono2018-07-031-2/+2
| | | | | | | | | | | 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.
* Use `reflection.alias_candidate` in `table_alias_for`Ryuta Kamizono2018-06-261-1/+1
| | | | | | | | | | | | | | | 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).
* Remove all `aliases` passing from `JoinDependency`Ryuta Kamizono2018-06-201-2/+2
| | | | Follow up of 15367a2c674bf19eeefa12ccb64391bdd50d883d.
* Remove useless `aliases` argument from `JoinDependency#construct`Ryuta Kamizono2018-06-201-5/+5
| | | | | Since `aliases` is a part of `JoinDependency` and already cached at 1a723c65bbe91ad969b67416233d20eff6d2a46a.
* Remove unused `rs` argument from `JoinDependency#construct`Ryuta Kamizono2018-06-201-5/+5
| | | | It was no longer used since d7ddaa530fd1b94e22d745cbaf2e8a5a34ee9734.
* Merge pull request #33158 from bogdan/cleanup-habtm-builderRyuta Kamizono2018-06-191-37/+16
|\ | | | | Removed useless utility classes inside HABTM association builder
| * Removed useless utility classes inside HABTM association builderBogdan Gusiev2018-06-191-37/+16
| |
* | Ensure to calculate column aliases after all table aliases are constructedRyuta Kamizono2018-06-193-58/+57
|/ | | | | | | | | | | | | | | | | 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.
* Don't use `target=`Rafael Mendonça França2018-06-111-1/+1
| | | | | It mark the association as loaded and this can cause the object to be in an stale state.
* Use `-=` to change the update the collection on the associationRafael Mendonça França2018-06-111-2/+1
| | | | | 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.
* Merge pull request #29939 from arthurchui/activerecord-delete-associations-loopRafael Mendonça França2018-06-111-1/+2
|\ | | | | | | Use hash lookup for deleting existing associations from `target`
| * Use hash lookup for deleting existing associations from `target`Arthur Chui2017-07-251-1/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | `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 ```
* | Fix alias confliction when joining same table on has many through with ↵Ryuta Kamizono2018-06-111-1/+1
| | | | | | | | | | | | | | | | | | | | 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.
* | Fix `collection.create` to could be rolled back by `after_save`Ryuta Kamizono2018-06-071-3/+9
| | | | | | | | | | | | | | | | | | | | | | 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.
* | Child joins should be aliased when merging relationsChalo Fernandez2018-06-061-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.