| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
|
|
|
|
|
| |
When `attr_name` is passed as a symbol, it's currently converted to a
string by `attribute_alias?`, and potentially also `attribute_alias`,
as well as by the `read_attribute`/`write_attribute` method itself.
By converting `attr_name` to a string up front, the extra allocations
related to attribute aliases can be avoided.
|
|
|
|
|
|
|
|
| |
Ruby uses the original method name, so will show the __temp__ method
name in the backtrace. However, in the common case the method name
is compatible with the `def` keyword, so we can avoid the __temp__
method name in that case to improve the name shown in backtraces
or TracePoint#method_id.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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'
|
|
|
|
|
|
|
| |
It should be done only once in `Persistence` module.
https://github.com/rails/rails/blob/c83e30da27eafde79164ecb376e8a28ccc8d841f/activerecord/lib/active_record/persistence.rb#L721
https://github.com/rails/rails/blob/c83e30da27eafde79164ecb376e8a28ccc8d841f/activerecord/lib/active_record/persistence.rb#L740
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
`changes_applied` should be called before continuing around callback
chain. Otherwise the mutation tracker returns old value for methods like
`changed`? or `id_in_database` in around callbacks. Also methods depend
on `id_in_database`, like `update_column`, are not working in
`around_create` callbacks.
```
class Foo < ActiveRecord::Base
around_create :around_create_callback
def around_create_callback
...
yield
p id_in_database # => nil
update_column(:generated_column, generate_value) # silently fails
end
...
end
```
|
|
|
|
|
|
| |
The first thing this method does is run on the argument. This change passes
in a string so we don't allocate a bunch of unnecessary extra strings by
calling to_s on a symbol over and over.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
`after_initialize`
`becomes` creates new object and copies attributes from the receiver. If
new object has mutation tracker which is created in `after_initialize`,
it should be cleared since it is for discarded attributes.
But if the receiver doesn't have mutation tracker yet, it will not be
cleared properly.
It should be cleared regardless of whether the receiver has mutation
tracker or not.
Fixes #32867.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Previously the documentation for the newly introduced (in 5.1) AR::Dirty
methods was misleading, as it stated the the new methods were aliases
for the old methods. This was false, and caused confusion when the
differences in their implementation became apparent.
This change attempts to describe the behaviour of these methods more
accurately, also noting when they are likely to be useful (i.e. before
or after saving a record).
This change also makes minor updates to consistently format the
documentation of this API, in accordance with the API Documentation
Guidelines.
|
|
|
|
|
| |
This commit fixes all references in the codebase missing a trailing :,
which causes the nodoc not to actually work :) [skip ci]
|
|
|
|
|
|
|
|
|
|
| |
`changed_attribute_names_to_save` is called in `keys_for_partial_write`,
which is called on every save when partial writes are enabled.
We can avoid generating the full changes hash by asking the mutation
tracker for just the names of the changed attributes. At minimum this
saves one array allocation per attribute, but will also avoid calling
`Attribute#original_value` which is expensive for serialized attributes.
|
| |
|
|
|
|
| |
This reverts commit a19e91f0fab13cca61acdb1f33e27be2323b9786.
|
|
|
|
|
| |
https://bugs.ruby-lang.org/issues/12752
https://ruby-doc.org/core-2.4.0/String.html#method-i-unpack1
|
|
|
|
|
| |
Some places we can't remove because Ruby still don't have a method
equivalent to strip_heredoc to be called in an already existent string.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
#30985 caused `object.save` performance regression since calling
`changes` in `changes_applied` is very slow.
We don't need to call the expensive method in `changes_applied` as long
as `@attributes` is tracked by mutation tracker.
https://gist.github.com/kamipo/1a9f4f3891803b914fc72ede98268aa2
Before:
```
Warming up --------------------------------------
create_string_columns
73.000 i/100ms
Calculating -------------------------------------
create_string_columns
722.256 (± 5.8%) i/s - 3.650k in 5.073031s
```
After:
```
Warming up --------------------------------------
create_string_columns
96.000 i/100ms
Calculating -------------------------------------
create_string_columns
950.224 (± 7.7%) i/s - 4.800k in 5.084837s
```
|
|
|
|
|
| |
Use these to back the attributes API. Stop automatically including
ActiveModel::Dirty in ActiveModel::Attributes, and make it optional.
|
|
|
|
| |
This basically reverts 9d4f79d3d394edb74fa2192e5d9ad7b09ce50c6d
|
|\
| |
| | |
activerecord: Remove a redundant mutation tracker
|
| |
| |
| |
| |
| |
| |
| | |
The extra mutation tracker was needed in Rails 5.1 to preserve the
old behaviour of `changes`, but now there is no difference
between `changes` and `changes_to_save`, so `@mutation_tracker`
can be removed.
|
|/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Benchmark Script:
```
require 'active_record'
require 'benchmark/ips'
ActiveRecord::Base.establish_connection(ENV.fetch('DATABASE_URL'))
ActiveRecord::Migration.verbose = false
ActiveRecord::Schema.define do
create_table :users, force: true do |t|
t.string :name, :email
t.integer :topic_id
t.timestamps null: false
end
create_table :topics, force: true do |t|
t.string :title
t.timestamps null: false
end
end
attributes = {
name: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
email: 'foobar@email.com'
}
class Topic < ActiveRecord::Base
has_many :users
end
class User < ActiveRecord::Base
belongs_to :topic
end
100.times do
User.create!(attributes)
end
users = User.first(50)
Topic.create!(title: 'This is a topic', users: users)
Benchmark.ips do |x|
x.config(time: 10, warmup: 5)
x.report("preload") do
User.includes(:topic).all.to_a
end
end
```
Before:
```
Calculating -------------------------------------
preload 40.000 i/100ms
-------------------------------------------------
preload 407.962 (± 1.5%) i/s - 4.080k
```
After:
```
alculating -------------------------------------
preload 43.000 i/100ms
-------------------------------------------------
preload 427.567 (± 1.6%) i/s - 4.300k
```
|
| |
|
| |
|
|
|
|
|
|
| |
`write_attribute_without_type_cast` is defined as a private method in
`AttributeMethods::Write`, but `AttributeMethods::Dirty` overrode it as
a public method. It should be kept the original visibility.
|
|
|
|
|
|
|
| |
We already have a test case for `serialize` with a custom coder in
`PostgresqlHstoreTest`.
https://github.com/rails/rails/blob/v5.1.3/activerecord/test/cases/adapters/postgresql/hstore_test.rb#L316-L335
|
|
|
|
|
| |
This module has behavior that is not present in `ActiveModel::Dirty`,
which is intended to be public API.
|
|\
| |
| | |
Do not let use `serialize` on native JSON/array column
|
| | |
|
|\ \
| |/
|/| |
Sync transaction state when accessing primary key
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
If a record is modified inside a transaction, it must check the outcome
of that transaction before accessing any state which would no longer be
valid if it was rolled back.
For example, consider a new record that was saved inside a transaction
which was later rolled back: it should be restored to its previous state
so that saving it again inserts a new row into the database instead of
trying to update a row that no longer exists.
The `id` and `id=` methods defined on the PrimaryKey module implement
this correctly, but when a model uses a custom primary key, the reader
and writer methods for that attribute must check the transaction state
too. The `read_attribute` and `write_attribute` methods also need to
check the transaction state when accessing the primary key.
|
| | |
|
| | |
|
| | |
|
|/ |
|
|\
| |
| | |
Improve the performance of writing attributes
|
| |
| |
| |
| |
| |
| |
| |
| | |
This name more accurately describes what the method does, and also
disambiguates it from `_write_attribute`, which ignores aliases.
We can also make the method private, since it's not public API and only
called from one place - `update_columns` - without an explicit receiver.
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
Using a similar approach to 08576b94ad4f19dfc368619d7751e211d23dcad8,
this change adds a new internal `_write_attribute` method which bypasses
the code that checks for attribute aliases and custom primary keys.
We can use this method instead of `write_attribute` when we know that we
have the name of the actual column to be updated and not an alias.
This makes writing an attribute with `attribute=` about 18% faster.
Benchmark:
```
begin
require "bundler/inline"
rescue LoadError => e
$stderr.puts "Bundler version 1.10 or later is required. Please update your Bundler"
raise e
end
gemfile(true) do
source "https://rubygems.org"
gem "rails", github: "rails/rails"
gem "arel", github: "rails/arel"
gem "sqlite3"
gem "benchmark-ips"
end
require "active_record"
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Schema.define do
create_table :posts, force: true do |t|
end
end
class Post < ActiveRecord::Base
end
post = Post.new(id: 1)
Benchmark.ips do |x|
x.report("attribute=") { post.id = post.id + 1 }
end
```
Before:
Warming up --------------------------------------
attribute= 25.889k i/100ms
Calculating -------------------------------------
attribute= 290.946k (± 3.1%) i/s - 1.476M in 5.077036s
After:
Warming up --------------------------------------
attribute= 30.056k i/100ms
Calculating -------------------------------------
attribute= 345.088k (± 4.8%) i/s - 1.743M in 5.064264s
|
|/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The `raw_write_attribute` method is used to update a record's attributes
to reflect the new state of the database in `update_columns`. The hash
provided to `update_columns` is turned into an UPDATE query directly,
which means passing an `id` key results in an update to the `id` column,
even if the model uses a different attribute as its primary key. When
updating the record, we don't want to apply the `id` column change to
the primary key attribute, since that's not what happened in the query.
Without the code to handle this case, `write_attribute_with_type_cast`
no longer contains any logic shared between `raw_write_attribute` and
`write_attribute`, so we can inline the code into those two methods.
|
|
|
|
|
| |
`sync_with_transaction_state` in `to_key` is unneeded because `id` also
does.
|
|
|
|
|
|
|
|
|
| |
Currently the methods of `AttributeMethods::PrimaryKey` are overwritten
by `define_attribute_methods`. It will be broken if a table that
customized primary key has non primary key id column.
It should not be overwritten if a table has any primary key.
Fixes #29350.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
* Allow a default value to be declared for class_attribute
* Convert to using class_attribute default rather than explicit setter
* Removed instance_accessor option by mistake
* False is a valid default value
* Documentation
|
|
|
|
|
|
| |
We already have a _read_attribute method that can get the value we need
from the model. Lets define that method in AM::Dirty and use the
existing one from AR::Dirty rather than introducing a new method.
|
| |
|
| |
|
|
|
|
|
|
|
| |
Since using a `ActiveSupport::Deprecation::DeprecatedConstantProxy`
would prevent people from inheriting this class and extending it
from the `ActiveSupport::HashWithIndifferentAccess` one would break
the ancestors chain, that's the best option we have here.
|
|
|
|
|
|
|
|
|
| |
Pointed out by @matthewd that the HWIA subclass changes the
AS scoped class and top-level HWIA hierarchies out from under
existing classes.
This reverts commit 71da39097b67114329be6d8db7fe6911124531af, reversing
changes made to 41c33bd4b2ec3f4a482e6030b6fda15091d81e4a.
|
|
|
|
|
|
|
|
|
| |
This constant was kept for the sake of backward compatibility; it
is still available under `ActiveSupport::HashWithIndifferentAccess`.
Furthermore, since Ruby 2.5 (https://bugs.ruby-lang.org/issues/11547)
won't support top level constant lookup, people would have to update
their code anyway.
|
|
|
|
|
|
| |
These files are not using `strip_heredoc`.
Closes #27976
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This was never really intended to work (at least not without calling
`define_attribute_methods`, which is less common with Active Record). As
we move forward the intention is to require the use of `attribute` over
`attr_accessor` for more complex model behavior both on Active Record
and Active Model, so this behavior is deprecated.
Fixes #27956.
Close #27963.
[Alex Serban & Sean Griffin]
|