aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/associations/builder/belongs_to.rb
Commit message (Collapse)AuthorAgeFilesLines
* Rename local variable `n` to `name`Ryuta Kamizono2019-04-241-2/+2
|
* Make association builder methods privateRyuta Kamizono2019-04-241-0/+3
|
* 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-271-37/+6
| | | | the belongs_to association
* Update counter cache in memory if parent target is existedRyuta Kamizono2018-09-261-10/+3
| | | | Fixes #19550.
* Don't update counter cache unless the record is actually savedRyuta Kamizono2018-09-191-3/+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.
* 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-301-6/+4
| | | | | | 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.
* Fix inconsistent touching behavior between assigning and unassigningRyuta Kamizono2018-05-271-1/+2
| | | | | | | | | | | 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-271-1/+1
|
* 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 conflicts `counter_cache` with `touch: true` by optimistic locking.bogdanvlviv2017-12-121-3/+7
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | ``` # create_table :posts do |t| # t.integer :comments_count, default: 0 # t.integer :lock_version # t.timestamps # end class Post < ApplicationRecord end # create_table :comments do |t| # t.belongs_to :post # end class Comment < ApplicationRecord belongs_to :post, touch: true, counter_cache: true end ``` Before: ``` post = Post.create! # => begin transaction INSERT INTO "posts" ("created_at", "updated_at", "lock_version") VALUES ("2017-12-11 21:27:11.387397", "2017-12-11 21:27:11.387397", 0) commit transaction comment = Comment.create!(post: post) # => begin transaction INSERT INTO "comments" ("post_id") VALUES (1) UPDATE "posts" SET "comments_count" = COALESCE("comments_count", 0) + 1, "lock_version" = COALESCE("lock_version", 0) + 1 WHERE "posts"."id" = 1 UPDATE "posts" SET "updated_at" = '2017-12-11 21:27:11.398330', "lock_version" = 1 WHERE "posts"."id" = 1 AND "posts"."lock_version" = 0 rollback transaction # => ActiveRecord::StaleObjectError: Attempted to touch a stale object: Post. Comment.take.destroy! # => begin transaction DELETE FROM "comments" WHERE "comments"."id" = 1 UPDATE "posts" SET "comments_count" = COALESCE("comments_count", 0) - 1, "lock_version" = COALESCE("lock_version", 0) + 1 WHERE "posts"."id" = 1 UPDATE "posts" SET "updated_at" = '2017-12-11 21:42:47.785901', "lock_version" = 1 WHERE "posts"."id" = 1 AND "posts"."lock_version" = 0 rollback transaction # => ActiveRecord::StaleObjectError: Attempted to touch a stale object: Post. ``` After: ``` post = Post.create! # => begin transaction INSERT INTO "posts" ("created_at", "updated_at", "lock_version") VALUES ("2017-12-11 21:27:11.387397", "2017-12-11 21:27:11.387397", 0) commit transaction comment = Comment.create!(post: post) # => begin transaction INSERT INTO "comments" ("post_id") VALUES (1) UPDATE "posts" SET "comments_count" = COALESCE("comments_count", 0) + 1, "lock_version" = COALESCE("lock_version", 0) + 1, "updated_at" = '2017-12-11 21:37:09.802642' WHERE "posts"."id" = 1 commit transaction comment.destroy! # => begin transaction DELETE FROM "comments" WHERE "comments"."id" = 1 UPDATE "posts" SET "comments_count" = COALESCE("comments_count", 0) - 1, "lock_version" = COALESCE("lock_version", 0) + 1, "updated_at" = '2017-12-11 21:39:02.685520' WHERE "posts"."id" = 1 commit transaction ``` Fixes #31199.
* Merge pull request #29765 from lugray/fix_counter_cacheRafael França2017-07-241-3/+1
|\ | | | | Fix `counter_cache` double increment
| * Add test for fixed `counter_cache` double incrementLisa Ugray2017-07-191-3/+1
| | | | | | | | | | | | | | | | | | | | | | When an `after_create` callback did `update_attributes` on a record with multiple `belongs_to` associations with counter caches, even numbered associations would have their counters double-incremented. Fixes to `ActiveModel::Dirty` in 020abad fixed this. This adds regression tests for this bug fixed incidentally in the other commit, which also removed the need for the workaround using @_after_create_counter_called.
* | Use frozen-string-literal in ActiveRecordKir Shatrov2017-07-191-0/+2
|/
* 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.
* Enforce frozen string in RubocopKir Shatrov2017-07-011-0/+1
|
* Evaluate the default block only when necessaryRyuta Kamizono2017-03-201-1/+1
| | | | Follow up of #28453.
* Add :default option to belongs_to (#28453)George Claghorn2017-03-171-1/+8
| | | | | | | | | | | Use it to specify that an association should be initialized with a particular record before validation. For example: # Before belongs_to :account before_validation -> { self.account ||= Current.account } # After belongs_to :account, default: -> { Current.account }
* Deprecate the behavior of AR::Dirty inside of after_(create|update|save) ↵Sean Griffin2016-11-011-14/+16
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | callbacks We pretty frequently get bug reports that "dirty is broken inside of after callbacks". Intuitively they are correct. You'd expect `Model.after_save { puts changed? }; model.save` to do the same thing as `model.save; puts model.changed?`, but it does not. However, changing this goes much farther than just making the behavior more intuitive. There are a _ton_ of places inside of AR that can be drastically simplified with this change. Specifically, autosave associations, timestamps, touch, counter cache, and just about anything else in AR that works with callbacks have code to try to avoid "double save" bugs which we will be able to flat out remove with this change. We introduce two new sets of methods, both with names that are meant to be more explicit than dirty. The first set maintains the old behavior, and their names are meant to center that they are about changes that occurred during the save that just happened. They are equivalent to `previous_changes` when called outside of after callbacks, or once the deprecation cycle moves. The second set is the new behavior. Their names imply that they are talking about changes from the database representation. The fact that this is what we really care about became clear when looking at `BelongsTo.touch_record` when tests were failing. I'm unsure that this set of methods should be in the public API. Outside of after callbacks, they are equivalent to the existing methods on dirty. Dirty itself is not deprecated, nor are the methods inside of it. They will only emit the warning when called inside of after callbacks. The scope of this breakage is pretty large, but the migration path is simple. Given how much this can improve our codebase, and considering that it makes our API more intuitive, I think it's worth doing.
* Fix counter_cache double increment bugTom Kadwill2016-04-281-0/+2
|
* Define `:foreign_type` as a valid option in `SingularAssociation`yui-knk2016-01-191-1/+1
| | | | | `:foreign_type` is a valid option for `belongs_to` and `has_one` so remove this to `SingularAssociation`.
* Make sure we touch all the parents when touch_later.Arthur Neves2015-12-061-2/+1
| | | | | | | | | | | | | | | | | | | | The problem was that when saving an object, we would call touch_later on the parent which wont be saved immediteally, and it wont call any callbacks. That was working one level up because we were calling touch, during the touch_later commit phase. However that still didnt solve the problem when you have a 3+ levels of parents to be touched, as calling touch would affect the parent, but it would be too late to run callbacks on its grand-parent. The solution for this, is instead, call touch_later upwards when the first touch_later is called. So we make sure all the timestamps are updated without relying on callbacks. This also removed the hard dependency BelongsTo builder had with the TouchLater module. So we can still have the old behaviour if TouchLater module is not included. [fixes 5f5e6d924973003c105feb711cefdb726f312768] [related #19324]
* Update belongs_to.rbEhsan Yousefi2015-11-081-2/+1
| | | There is no need to to assign reflection name to a variable, because it's called once.
* docs, add missing `:nodoc: for `Associations::Builder`. [ci skip]Yves Senn2015-10-131-1/+1
| | | | | | This class is only used internally. We should keep it out of public documentation. This patch adds nodoc for `ActiveRecord::Associations::Builder` and everything nested within.
* Fix counter_cache for polymorphic associationsStefan Kanev2015-07-191-4/+12
| | | | | | | | | | | | | | Also removes a false positive test that depends on the fixed bug: At this time, counter_cache does not work with polymorphic relationships (which is a bug). The test was added to make sure that no StaleObjectError is raised when the car is destroyed. No such error is currently raised because the lock version is not incremented by appending a wheel to the car. Furthermore, `assert_difference` succeeds because `car.wheels.count` does not check the counter cache, but the collection size. The test will fail if it is replaced with `car.wheels_count || 0`.
* Batch touch parent recordsArthur Neves2015-04-081-6/+7
| | | | | | | | | | [fixes #18606] Make belongs_to use touch over touch_later when running the callbacks. Add more tests and small method rename Thanks Jeremy for the feedback.
* Require `belongs_to` by default.Josef Šimánek2015-02-211-1/+19
| | | | Deprecate `required` option in favor of `optional` for belongs_to.
* Remove support to activerecord-deprecated_findersRafael Mendonça França2015-01-021-4/+2
|
* Merge pull request #12450 from iantropov/masterRafael Mendonça França2014-06-271-0/+5
|\ | | | | | | | | | | | | | | | | Fix bug, when ':dependent => :destroy' violates foreign key constraints Conflicts: activerecord/CHANGELOG.md activerecord/lib/active_record/associations/builder/association.rb activerecord/lib/active_record/associations/builder/has_one.rb
| * Fix bug, when ':dependent => :destroy' option violates foreign key ↵Ivan Antropov2013-10-261-0/+4
| | | | | | | | constraints, issue #12380
* | Prevented belongs_to: touch propagating up if there are no changes being savedBrock Trappitt2014-05-211-1/+1
| |
* | Hide BelongsToAssociation#increment_counters and #decrement_countersJean Boussier2014-04-151-1/+0
| |
* | Use inheritance chain instead of callbacks to increment counter caches after ↵Jean Boussier2014-04-141-16/+0
| | | | | | | | destroy
* | Use inheritance chain instead of callbacks to increment counter caches after ↵Jean Boussier2014-04-141-12/+1
| | | | | | | | create
* | Make counter cache decrementation on destroy idempotentJean Boussier2014-04-131-4/+5
| |
* | On destroying do not touch destroyed belongs to association.Paul Nikitochkin2013-12-231-1/+1
| | | | | | | | Fixes: #13445
* | Revert the whole refactoring in the association builder classes.Rafael Mendonça França2013-12-111-2/+4
| | | | | | | | This is to get activerecord-deprecated_finders work again
* | Bring back the valid_options class accessorRafael Mendonça França2013-12-111-1/+1
| | | | | | | | It is need in activerecord-deprecated_finders
* | polymorphic belongs_to association with touch: true updates old record correctlySeverin Schoepke2013-12-051-1/+7
| | | | | | | | | | | | | | | | | | Example: Given you have a comments model with a polymorphic commentable association (e.g. books and songs) with the touch option set. Every time you update a comment its commentable should be touched. This was working when you changed attributes on the comment or when you moved the comment from one book to another. However, it was not working when moving a comment from a book to a song. This is now fixed.
* | Raise `ArgumentError` when `has_one` is used with `counter_cache`Godfrey Chan2013-11-291-1/+1
| | | | | | | | | | | | | | | | | | Previously, the `has_one` macro incorrectly accepts the `counter_cache` option due to a bug, although that options was never supported nor functional on `has_one` and `has_one ... through` relationships. It now correctly raises an `ArgumentError` when passed that option. For reference, this bug was introduced in 52f8e4b9.
* | Method visibility will not make difference hereRafael Mendonça França2013-10-091-2/+0
| |
* | Move macro to class levelRafael Mendonça França2013-10-091-1/+1
| |
* | Make valid_options a class methodRafael Mendonça França2013-10-091-1/+1
| |
* | Push define_accessors to class level since we don't need anythig fromRafael Mendonça França2013-10-081-2/+2
| | | | | | | | the instance
* | Move add_counter_cache_methods to class levelRafael Mendonça França2013-10-081-2/+2
| |
* | we can define callbacks without a builder instanceAaron Patterson2013-10-021-3/+3
| |
* | push methods that don't depend on the instance to the classAaron Patterson2013-10-021-4/+4
| |
* | decouple belongs_to callback definition from the builder instance.Aaron Patterson2013-10-021-4/+4
| | | | | | | | All the information is on the reflection, so just get it there.