| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
| |
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 #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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
|
|
|
| |
when model is added to collection association
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
```
# 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.
|
| |
|
| |
|
|
|
|
|
| |
This reverts commit 3420a14590c0e6915d8b6c242887f74adb4120f9, reversing
changes made to afb66a5a598ce4ac74ad84b125a5abf046dcf5aa.
|
| |
|
| |
|
|
|
|
| |
Follow up of #28453.
|
|
|
|
|
|
|
|
|
|
|
| |
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 }
|
| |
|
| |
|
| |
|
|
|
|
|
|
|
|
| |
relationship without the foreign key attribute
fixes regression reported on #20253
ActiveRecord::Base#[] was not used cause of 8b95420
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
When we made sure that the counter gets updated in memory, we only did
it on the has many side. The has many side only does the update if the
belongs to cannot. The belongs to side was updated to update the counter
cache (if it is able). This means that we need to check if the
belongs_to is able to update in memory on the has_many side.
We also found an inconsistency where the reflection names were used to
grab the association which should update the counter cache. Since
reflection names are now strings, this means it was using a different
instance than the one which would have the inverse instance set.
Fixes #18689
[Sean Griffin & anthonynavarre]
|
|
|
|
|
|
|
|
|
|
|
|
| |
`ActiveRecord::Base#[]` has overhead that was introduced in 4.2. The
`foo["id"]` working with PKs other than ID isn't really a case that we
want to support publicly, but deprecating was painful enough that we
avoid it. `_read_attribute` was introduced as the faster alternative for
use internally. By using that, we can save a lot of overhead. We also
save some overhead by reading the attribute one fewer times in
`stale_state`.
Fixes #18151
|
|
|
|
|
|
| |
Instead of checking for `macro == :has_one` throughout the
codebase we can create a `has_one?` method to match the `belongs_to?`,
`polymorphic?` and other methods.
|
| |
|
|
|
|
| |
create
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
|
|
|
|
| |
calling replace_keys could possibly do a nil check twice, this commit
reduces it to once.
|
|
|
|
|
| |
methods that call set_inverse_instance with a record will not have to
pay the cost of a nil check on every call
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
|
|
|
|
|
|
| |
* Remove unused association_class method.
* Remove a unnecessary assignment.
* Move @updated to BelongsToAssociation that only reference this instance variable.
* Reset @stale_state at the reset method. I think this place is right place.
|
|
|
|
| |
Closes #3104.
|
| |
|
| |
|
| |
|
|
|
|
| |
'reflection.options' with 'options'. Also add through_options and source_options methods for through associations.
|
|
|
|
| |
proxy type on assignment.
|
|
|
|
| |
accessing the instance variables
|
| |
|
| |
|
| |
|