aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/associations
Commit message (Collapse)AuthorAgeFilesLines
...
* 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.
* | Initialization block is a part of `build_record`Ryuta Kamizono2018-06-046-14/+10
| | | | | | | | Should be done before `before_add` callbacks.
* | Fix inconsistent touching behavior between assigning and unassigningRyuta Kamizono2018-05-272-2/+3
| | | | | | | | | | | | | | | | | | | | | | 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.
* | Fix `belongs_to_counter_cache_after_update` to respect polymorphic type changeRyuta Kamizono2018-05-273-2/+9
| |
* | Avoid a subquery in updating counter cacheRyuta Kamizono2018-05-261-6/+1
| | | | | | | | Since UPDATE with a subquery doesn't work on MySQL.
* | Fix `belongs_to_counter_cache_after_update` to respect custom primary key ↵Ryuta Kamizono2018-05-261-0/+13
| | | | | | | | | | | | | | | | | | | | 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.
* | Fix `different_target?` to respect custom primary key counterRyuta Kamizono2018-05-261-3/+6
| |
* | Eager loading won't mutate owner recordRyuta Kamizono2018-05-252-11/+19
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.
* | Don't expose `SingularAssociation#replace` which is internal APIRyuta Kamizono2018-05-163-47/+44
| | | | | | | | | | Originally `SingularAssociation#replace` abstract method is private, and doesn't intend to be called directly.
* | Allow a belonging to object to be created from a new recordJolyon Pawlyn2018-05-012-4/+8
| | | | | | | | 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.
* | Ensure that `ids_reader` respects dirty target whether target is loaded or notRyuta Kamizono2018-04-271-1/+3
| | | | | | | | | | | | | | 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.
* | Loaded associations should not run a new query when size is calledGraham Turner2018-04-261-1/+3
| | | | | | | | | | | | | | 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
* | Merge pull request #32514 from ↵Ryuta Kamizono2018-04-221-1/+5
|\ \ | | | | | | | | | | | | samdec/multiple-has-one-through-associations-build-bug Fix .new with multiple through associations
| * | Fix .new with multiple through associationsSam DeCesare2018-04-091-1/+5
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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.