| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
As of [Revision 66772](
https://bugs.ruby-lang.org/projects/ruby-trunk/repository/trunk/revisions/66772)
`Proc.new` without giving a block emits `warning: tried to create Proc object without a block`.
This commit fixes cases where Rails test suit tickles this warning.
See CI logs:
https://travis-ci.org/rails/rails/jobs/487205819#L1161-L1190
https://travis-ci.org/rails/rails/jobs/487205821#L1154-1159
https://travis-ci.org/rails/rails/jobs/487205821#L1160-L1169
https://travis-ci.org/rails/rails/jobs/487205821#L1189
https://travis-ci.org/rails/rails/jobs/487254404#L1307-L1416
https://travis-ci.org/rails/rails/jobs/487254405#L1174-L1191
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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'
|
|
|
|
| |
Since counter cache handles touch option too.
|
|
|
|
| |
the belongs_to association
|
|
|
|
| |
Fixes #19550.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
| |
To prevent style check in review like https://github.com/rails/rails/pull/33608#discussion_r211087605.
|
|
|
|
|
|
| |
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 UPDATE with a subquery doesn't work on MySQL.
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
| |
Follow up of 09cac8c67afdc4b2a1c6ae07931ddc082629b277.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
```
# 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.
|
|
|
|
| |
Removed unnecessary semicolons
|
|
|
|
| |
This basically reverts 9d4f79d3d394edb74fa2192e5d9ad7b09ce50c6d
|
|
|
|
| |
`options` is never assigned to `scope` as long as using splat hash.
|
|\
| |
| | |
Fix `counter_cache` double increment
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
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.
|
|/ |
|
| |
|
| |
|
|
|
|
| |
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 }
|
|
|
|
|
|
| |
Some methods were added to public API in
5b14129d8d4ad302b4e11df6bd5c7891b75f393c and they should be not part of
the public API.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This patch brings back the functionality of passing true to the
association proxy. The behavior was deprecated with #20888 and scheduled
for removal in Rails 5.1.
The deprecation mentioned that instead of `Article.category(true)` one
should use `article#reload.category`. Unfortunately the alternative does
not expose the same behavior as passing true to the reader
did. Specifically reloading the parent record throws unsaved changes and
other caches away. Passing true only affected the association.
This is problematic and there is no easy workaround. I propose to bring
back the old functionality by introducing this new reader method for
singular associations.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Using Constant and symbol class_name option for associations are valid but raises exception on HABTM associations.
There was a test case which tries to cover symbol class_name usage but doesn't cover correctly. Fixed both symbol usage and constant usage as well.
These are all working as expected now;
```
has_and_belongs_to_many :foos, class_name: 'Foo'
has_and_belongs_to_many :foos, class_name: :Foo
has_and_belongs_to_many :foos, class_name: Foo
```
Closes #23767
|
| |
|
| |
|
|
|
|
|
| |
The current code base is not uniform. After some discussion,
we have chosen to go with double quotes by default.
|
|
|
|
|
|
|
|
|
|
|
| |
Actually schema dumper/creation supports composite primary key (#21614).
Therefore it should not show the warning about composite primary key in
connection adapter.
This change moves the warning to `AttributeMethods::PrimaryKey` and
suppress the warning for habtm join table.
Fixes #25388.
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Closes #23934.
This is a forward port of ac832a43b4d026dbad28fed196d2de69ec9928ac
Previously the scope of all associations with extensions were wrapped in
an instance dependent proc. This made it impossible to preload such
associations.
|
|
|
|
|
|
|
|
| |
habtm join tables commonly have two id columns and it's OK to make those
two id columns a primary key. This commit eliminates the warnings for
join tables that have this setup.
ManageIQ/manageiq#6713
|
|
|
|
|
| |
`:foreign_type` is a valid option for `belongs_to` and `has_one`
so remove this to `SingularAssociation`.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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]
|
|
|
| |
There is no need to to assign reflection name to a variable, because it's called once.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Before this commit, if
`ActiveRecord::Base.belongs_to_required_by_default` is set to `true`,
then creating a record through `has_and_belongs_to_many` fails with the
cryptic error message `Left side must exist`. This is because
`inverse_of` isn't working properly in this case, presumably since we're
doing trickery with anonymous classes in the middle.
Rather than following this rabbit hole to try and get `inverse_of` to
work in a case that we know is not publicly supported, we can just turn
off this validation to match the behavior of 4.2 and earlier.
|
|\
| |
| |
| |
| |
| | |
Errors can be indexed with nested attributes
Close #8638
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
`has_many` can now take `index_errors: true` as an
option. When this is enabled, errors for nested models will be
returned alongside an index, as opposed to just the nested model name.
This option can also be enabled (or disabled) globally through
`ActiveRecord::Base.index_nested_attribute_errors`
E.X.
```ruby
class Guitar < ActiveRecord::Base
has_many :tuning_pegs
accepts_nested_attributes_for :tuning_pegs
end
class TuningPeg < ActiveRecord::Base
belongs_to :guitar
validates_numericality_of :pitch
end
```
- Old style
- `guitar.errors["tuning_pegs.pitch"] = ["is not a number"]`
- New style (if defined globally, or set in has_many_relationship)
- `guitar.errors["tuning_pegs[1].pitch"] = ["is not a number"]`
[Michael Probber, Terence Sun]
|
| |
| |
| |
| |
| |
| | |
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.
|
| | |
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
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`.
|
|/
|
|
|
|
|
|
|
|
|
|
|
| |
In 1f006c an option was added called :class to allow passing anonymous
classes to association definitions. Since using :class instead of
:class_name is a fairly common typo even amongst experienced developers
this can result in hard to debug errors arising in raise_on_type_mismatch?
To fix this we're renaming the option from :class to :anonymous_class as
that is a more correct description of what the option is for. Since this
was an internal, undocumented option there is no need for a deprecation.
Fixes #19659
|
|
|
|
|
|
|
|
|
|
| |
[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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
https://github.com/ruby/ruby/pull/579 - there is a new optimization
since ruby 2.2
Previously regexp patterns were faster (since a string was converted to
regexp underneath anyway). But now string patterns are faster and
better reflect the purpose.
Benchmark.ips do |bm|
bm.report('regexp') { 'this is ::a random string'.gsub(/::/, '/') }
bm.report('string') { 'this is ::a random string'.gsub('::', '/') }
bm.compare!
end
# string: 753724.4 i/s
# regexp: 501443.1 i/s - 1.50x slower
|