aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/associations/collection_association.rb
Commit message (Collapse)AuthorAgeFilesLines
* Use compact_blank throughout railsDana Sherson2019-06-051-1/+1
|
* Revert "Merge pull request #35127 from bogdan/counter-cache-loading"Ryuta Kamizono2019-02-131-2/+1
| | | | | | | | | | | | | This reverts commit eec3e28a1abf75676dcee58308ee5721bb53c325, reversing changes made to 5588fb4802328a2183f4a55c36d6703ee435f85c. Reason: Marking as loaded without actual loading is too greedy optimization. See more context #35239. Closes #35239. [Edouard CHIN & Ryuta Kamizono]
* Merge pull request #35178 from bogdan/has-many-sizeRyuta Kamizono2019-02-081-2/+2
|\ | | | | Bugfix has_many association #size when ids reader is cached and assoc…
| * Bugfix has_many association #size when ids reader is cached and association ↵Bogdan Gusiev2019-02-081-2/+2
| | | | | | | | is changed
* | Fix `CollectionProxy#concat` to return self by alias it to `#<<`Yuya Tanaka2019-02-061-3/+2
|/ | | | Formerly it was returning arguments (`records` array).
* Bugfix association loading behavior when counter cache is zeroBogdan Gusiev2019-02-051-2/+3
|
* Merge pull request #34806 from bogdan/reuse-find-targetRyuta Kamizono2018-12-271-16/+0
|\ | | | | | | Reuse AR::Association#find_target method
| * Reuse AR::Association#find_target methodBogdan Gusiev2018-12-271-15/+0
|/
* Revert "Merge pull request #34538 from bogdan/reuse-find-target"Ryuta Kamizono2018-11-281-0/+15
| | | | | | | 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-271-16/+0
| | | | | | | 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.
* Rename union to intersectionFlorian Ebeling2018-11-061-1/+1
|
* Fix handling of duplicates for `replace` on has_many-throughFlorian Ebeling2018-11-061-3/+3
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | 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 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 `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.
* | Initialization block is a part of `build_record`Ryuta Kamizono2018-06-041-5/+2
| | | | | | | | Should be done before `before_add` callbacks.
* | 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
* | `target` in `CollectionAssociation` is always an arrayRyuta Kamizono2018-04-211-2/+2
| | | | | | | | | | So `target.is_a?(Array)` is meaningless, and just use `target.empty?` instead of `target.blank?`.
* | Avoid extra calls to to_sDaniel Colson2018-01-291-1/+1
| | | | | | | | | | | | | | 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.
* | Remove `association_primary_key_type` from `AssociationReflection` and ↵Ryuta Kamizono2018-01-011-2/+2
| | | | | | | | | | | | | | | | `ThroughReflection` This method was introduced in #26718, which is internally used only in `CollectionAssociation`. There is no need to be in the reflection classes.
* | Provide arguments to RecordNotFoundNikita Misharin2017-11-251-1/+7
| |
* | Move duplicated code to `delete_or_destroy` in `CollectionAssociation`Ryuta Kamizono2017-10-061-4/+2
| |
* | Merge pull request #27609 from kamipo/fix_association_primary_keyRafael França2017-08-141-4/+7
|\ \ | | | | | | Fix `reflection.association_primary_key` for `has_many` association
| * | Fix `reflection.association_primary_key` for `has_many` associationsRyuta Kamizono2017-08-131-4/+7
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | It is incorrect to treat `options[:primary_key]` as `association_primary_key` if `has_many` associations because the `:primary_key` means the column on the owner record, not on the association record. It will break `ids_reader` and `ids_writer`. ```ruby people(:david).essay_ids # => ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'essays.first_name' in 'field list': SELECT `essays`.first_name FROM `essays` WHERE `essays`.`writer_id` = 'David' ``` Fixes #14439.
* | | Delegate to `Enumerable#find` for `CollectionProxy`Ryuta Kamizono2017-08-131-15/+11
|/ / | | | | | | | | Since `Relation` includes `Enumerable`, it is enough to use `super` simply.
* | Merge pull request #29720 from gaurish/ar_find_error_message_improvementRafael França2017-08-111-1/+3
|\ \ | | | | | | Return Not found Ids in ActiveRecord::NotFound
| * | Return Not found Ids in ActiveRecord::NotFoundGaurish Sharma2017-07-291-1/+3
| |/ | | | | | | | | This builds on top of 15e2da656f41af0124f7577858536f3b65462ad5. now it also returns exact Ids which were not found which will be debugging simple.
* / Passing `klass` to `StatementCache.new`Ryuta Kamizono2017-08-041-6/+4
|/ | | | | | Actually `StatementCache#execute` is always passed the same klass that the owner klass of the connection when the statement cache is created. So passing `klass` to `StatementCache.new` will make more DRY.
* Use frozen-string-literal in ActiveRecordKir Shatrov2017-07-191-0/+2
|
* Fix `create_with` using both string and symbolRyuta Kamizono2017-07-161-4/+0
| | | | | | | This is related with #27680. Since `where_values_hash` keys constructed by `where` are string, so we need `stringify_keys` to `create_with_value` before merging it.
* Revert "Merge pull request #29540 from kirs/rubocop-frozen-string"Matthew Draper2017-07-021-1/+0
| | | | | This reverts commit 3420a14590c0e6915d8b6c242887f74adb4120f9, reversing changes made to afb66a5a598ce4ac74ad84b125a5abf046dcf5aa.
* Merge pull request #29540 from kirs/rubocop-frozen-stringMatthew Draper2017-07-021-0/+1
|\ | | | | | | Enforce frozen string in Rubocop
| * Enforce frozen string in RubocopKir Shatrov2017-07-011-0/+1
| |
* | Should be clear `@association_ids` when joined newly associated recordRyuta Kamizono2017-06-301-2/+11
|/ | | | Fixes #29627.
* Merge pull request #29610 from ↵Rafael França2017-06-281-1/+1
|\ | | | | | | | | kamipo/dont_passing_klass_connection_to_association_scope Don't passing `klass.connection` to `AssociationScope`
| * Don't passing `klass.connection` to `AssociationScope`Ryuta Kamizono2017-06-291-1/+1
| | | | | | | | | | Passing `klass.connection` is redundant because `AssociationScope` is passed an association itself and an association has `klass`.
* | Fix `ids_reader` to respect case sensitive primary keyRyuta Kamizono2017-06-281-4/+1
|/ | | | | | | | | | | | ```ruby car = Car.create!(name: "Tofaş") # Before car.bulb_ids # => SELECT "bulbs".ID FROM "bulbs" WHERE "bulbs"."name" = $1 AND "bulbs"."car_id" = $2 [["name", "defaulty"], ["car_id", 3]] # After car.bulb_ids # => SELECT "bulbs"."ID" FROM "bulbs" WHERE "bulbs"."name" = $1 AND "bulbs"."car_id" = $2 [["name", "defaulty"], ["car_id", 3]] ```
* Prevent extra `scope` construction in `find_target`Ryuta Kamizono2017-06-181-1/+2
| | | | Because constructing `scope` is a little expensive.
* Cache the association proxy objectRyuta Kamizono2017-05-281-1/+2
| | | | | | | | | | Some third party modules expects that association returns same proxy object each time (e.g. for stubbing collection methods: https://github.com/rspec/rspec-rails/issues/1817). So I decided that cache the proxy object and reset scope in the proxy object each time. Related context: https://github.com/rails/rails/commit/c86a32d7451c5d901620ac58630460915292f88b#commitcomment-2784312
* Prevent double firing the before save callback of new object when the parent ↵Ryuta Kamizono2017-04-211-35/+32
| | | | | | | | | | | | | | | | | | association saved in the callback Related #18155, #26661, 268a5bb, #27434, #27442, and #28599. Originally #18155 was introduced for preventing double insertion caused by the after save callback. But it was caused the before save issue (#26661). 268a5bb fixed #26661, but it was caused the performance regression (#27434). #27442 added new record to `target` before calling callbacks for fixing #27434. But it was caused double firing before save callback (#28599). We cannot add new object to `target` before saving the object. This is improving #18155 to only track callbacks after `save`. Fixes #28599.
* Merge pull request #25877 from kamipo/delegate_to_scope_rather_than_mergeMatthew Draper2017-02-211-10/+4
|\ | | | | Delegate to `scope` rather than `merge!` for collection proxy
| * No need to cache collection proxies separatelyRyuta Kamizono2016-12-251-7/+1
| | | | | | | | Because merging the association scope was removed.
| * Delegate to `scope` rather than `merge!` for collection proxyRyuta Kamizono2016-12-251-3/+3
| | | | | | | | | | `merge! association.scope(nullify: false)` is expensive but most methods do not need the merge.
* | Merge pull request #26352 from kamipo/avoid_to_call_set_inverse_instance_twiceArthur Nogueira Neves2017-01-031-1/+2
|\ \ | | | | | | Avoid to call `set_inverse_instance` twice for `has_many` association
| * | Avoid to call `set_inverse_instance` twice for `has_many` associationRyuta Kamizono2016-12-281-1/+2
| | | | | | | | | | | | | | | `create`, `create!`, and `concat` in `has_many` association hits `set_inverse_instance` twice. It is enough to hit only once.
* | | Refactor `CollectionAssociation#ids_reader`Ryuta Kamizono2017-01-011-3/+1
| | | | | | | | | | | | | | | Simply we can do `target.pluck(reflection.association_primary_key)` if `target` is loaded.
* | | Remove deprecated force reload argument in association readersRafael Mendonça França2016-12-291-10/+2
|/ /