This can cause a lot of issues that are hard to detect.
It is better to make this opt-in for people that want to use it.
In Rails 8 we can revisit if we want to enable this config by default.
Upstream sqlite updated the error messages to be more descriptive
starting in v3.46.0. Where the error message might look like this in
earlier versions:
no such column: non_existent
in 3.46.0 it looks like:
no such column: "non_existent" - should this be a string literal in single-quotes?
The tests have been updated to accept either style of message.
The sqlite3-ruby gem will release a version with this vendored version
shortly, see https://github.com/sparklemotion/sqlite3-ruby/pull/536
Previously we only provided a method to set the ignored schema cache
tables, but there was no way to ask if a table was ignored by the schema
cache. Applications may want to implement their own schema cache, or at
least run this check. Rather than forcing them to implement an internal
method, this adds a way to ask whether a table is ignored by the schema
cache code.
Usage:
```ruby
ActiveRecord.schema_cache_ignored_tables = ["developers"]
ActiveRecord.schema_cache_ignored_tables?("developers")
```
PostgreSQL Cidr#change? raise an error of NoMethodError: undefined method `prefix' for nil, when creating a record with an empty value of inet/cidr column.
Fix: https://github.com/rails/rails/issues/51807
`association_cached?` only means the Association object was
created, not that the records were loaded.
Co-Authored-By: benk-gc <bkyriakou@gocardless.com>
Ref: https://github.com/rails/rails/pull/50396
Ref: https://github.com/rails/rails/pull/51776
`ActiveRecord::Relation` automatically delegates missing methods
to the model class wrapped in a `scoping { }` block.
This is to support scoping in user defined class methods. The problem
however is that it's very error prone for the framework, because we
can mistakenly call model methods from inside `Relation` and not
realized we're applying a global scope.
In the best case scenario it's just a waste of performance, but
it can also lead to bugs like https://github.com/rails/rails/issues/51775
I'm planning to restrict this automatic delegation to methods defined
in childs of `ActiveRecord::Base` only: https://github.com/rails/rails/pull/50396
but for this to work we must first refactor any Rails code that rely on it.
Ref: https://github.com/rails/rails/pull/50396
Ref: https://github.com/rails/rails/pull/51776
`ActiveRecord::Relation` automatically delegates missing methods
to the model class wrapped in a `scoping { }` block.
This is to support scoping in user defined class methods. The problem
however is that it's very error prone for the framework, because we
can mistakenly call model methods from inside `Relation` and not
realized we're applying a global scope.
In the best case scenario it's just a waste of performance, but
it can also lead to bugs like https://github.com/rails/rails/issues/51775
I'm planning to restrict this automatic delegation to methods defined
in childs of `ActiveRecord::Base` only: https://github.com/rails/rails/pull/50396
but for this to work we must first refactor any Rails code that rely on it.
which respects reject_if and is in nested_attributes order.
When in default index_errors:true mode,
fix#24390 and return index based on full association order.
This commit adds a deprecation warning for the `query_constraints:`
association option. This option will change behavior in the future versions
of Rails and applications are encouraged to switch to `foreign_key:` to preserve the
current behavior.
We're already conditioning `reflection_fk` based on whether it's an
`Array` or not, so no need to wrap it in this `Array()` call since in
this block it is sure to be an `Array`.
Ref.: d7980c6b10
Using the same benchmark as in https://github.com/rails/rails/pull/51726
`replace_keys` always allocate a multiple arrays to support composite
primary keys, even though most primary keys likely aren't composite.
And even when they are, we can avoid needless allocations by not using
`Array#zip`.
This reduce allocations by 18% (8k) on that benchmark.
Before:
```
Total allocated: 4.88 MB (44495 objects)
Total retained: 4.16 MB (32043 objects)
allocated memory by file
-----------------------------------
...
320.00 kB activerecord/lib/active_record/associations/belongs_to_association.rb
allocated objects by file
-----------------------------------
...
8000 activerecord/lib/active_record/associations/belongs_to_association.rb
```
After:
```
Total allocated: 4.56 MB (36495 objects)
Total retained: 4.16 MB (32041 objects)
```
NB: `belongs_to_association` doesn't show up in top files anymore
Last big refactor was in https://github.com/rails/rails/pull/37614.
Somewhat extracted from https://github.com/rails/rails/pull/51744.
The concern about columns with the same name didn't make much sense
to me because in both code paths, the last one wins, so we can simplify
the whole methods.
Additionally by implementing `columns_index`, we have a decent template
always available.
Using a simple benchmark such as:
```ruby
Post.transaction do
100.times do
post = Post.create!(author_id: 42, title: "A" * 50, body: "a" * 400, tags: "blah blah blah", published_at: Time.now, comments_count: 20)
20.times do
post.comments.create!(author_id: 42, body: "a" * 120, tags: "blah blah blah", published_at: Time.now)
end
end
end
posts = Post.includes(:comments).to_a
```
This allocate `43,077` objects, and out of these `2,200` are caused by association
names being stored as strings internally:
```
Allocated String Report
-----------------------------------
80.00 kB 2000 "post"
2000 activerecord/lib/active_record/reflection.rb:123
8.00 kB 200 "comments"
200 activerecord/lib/active_record/reflection.rb:123
```
This is because many API accept either symbol or string, and blindly
call `to_s` on it. We could avoid this with sprinkling the code with
`Symbol == association ? association.name : association.to_s`, but it's
ugly.
This issue may be entirely solved in a future Ruby version, but
it will take years: https://bugs.ruby-lang.org/issues/20350
By using symbols, we both save allocations, and marginally speed up
lookups and comparisons, reducing this particular benchmark allocations
by 5%.
It's a bit unclear why these were ever made strings. Historically
symbols were immortal and using them for user supplied data could lead
to DOS vulnerability, so this may have been why, but it's not longer
a concern since Ruby 2.2.
I'm looking at reducing the allocations and memory footprint
of Active Record models, and based on a small benchmark I saw
a lot of numeric strings being created from `stale_state`.
I tracked this cast all the way down to 1c07b84df9
but unfortunately the commit message doesn't explain why it was added.
I can't think of a reason why this would be needed.
The benchmark is essentially just: `Post.includes(:comments).to_a` with
`100` posts and `20` comments each.
```
Total allocated: 4.69 MB (45077 objects)
Total retained: 3.84 MB (29623 objects)
retained objects by location
-----------------------------------
...
2000 activerecord/lib/active_record/associations/belongs_to_association.rb:152
retained memory by location
-----------------------------------
...
80.00 kB activerecord/lib/active_record/associations/belongs_to_association.rb:152
```
NB: This break the final assertion of the Rails 6.1 Marshal backward compatibility
test, but I think it's an acceptable tradeoff.
```ruby
Post.with_recursive(
post_and_replies: [
Post.where(id: 42),
Post.joins('JOIN post_and_replies ON posts.in_reply_to_id = post_and_replies.id'),
]
)
```
Generates the following SQL:
```sql
WITH RECURSIVE "post_and_replies" AS (
(SELECT "posts".* FROM "posts" WHERE "posts"."id" = 42)
UNION ALL
(SELECT "posts".* FROM "posts" JOIN post_and_replies ON posts.in_reply_to_id = post_and_replies.id)
)
SELECT "posts".* FROM "posts"
```
at the connection level
Fix#51448
Type cast columns of type `date` to ruby `Date` when running a raw
query through `ActiveRecord::Base.connection.select_all`.
Update activerecord/lib/active_record/connection_adapters/postgresql/oid/cidr.rb
Co-authored-by: Yasuo Honda <yasuo.honda@gmail.com>
Updated to keep the argument order
Added note to remove `changed?` method when `IPAddr#==` compares `IPAddr#prefix`
Ref: https://bugs.ruby-lang.org/issues/15554
A couple are harmless, but another couple found actual problems
in the test suite where we passed blocks to `assert_*` methods that
didn't expect one.
Before:
```ruby
person = Person.find(1)
person.strict_loading!(mode: :n_plus_one_only)
person.posts.first
# SELECT * FROM posts WHERE person_id = 1; -- non-deterministic order
```
After:
```ruby
person = Person.find(1)
person.strict_loading!(mode: :n_plus_one_only)
person.posts.first # this is 1+1, not N+1
# SELECT * FROM posts WHERE person_id = 1 ORDER BY id LIMIT 1;
```
Strict loading in `:n_plus_one_only` mode is designed to prevent performance issues when
deeply traversing associations. It allows `Person.find(1).posts`, but _not_
`Person.find(1).posts.map(&:category)`. With this change, child associations are no
longer eagerly loaded, to match intended behavior and to prevent non-deterministic
order issues caused by calling methods like `first` or `last`.
Fixes#49473.
Testing against upstream sqlite3 which returns frozen strings
demonstrates that Rails can't guarantee that the schema dumps will be
byte-for-byte reproducible when they're in Marshal format.
Accidentally `remove_prefix_and_suffix` in `ActiveRecord::SchemaDumper`
has broken due to table name prefix and suffix options is assigned to
unused `version` argument in `SchemaDumper#initialize` added in #51162.
This commit fixes generated SQL for `UNION` and `UNION ALL` involving `LIMIT`
or `ORDER BY` by wrapping `SELECT` statements appearing in an `UNION` or
`UNION ALL` in parentheses.
Similar to 50515fb45f, make sure we
require `ostruct` where we use `OpenStruct`, to get the build back to
green, while we work to remove its usage on tests. (see #51510.)
Sample error:
```
Error:
ActiveRecord::Encryption::ConfigurableTest#test_installing_autofiltered_parameters_will_add_the_encrypted_attribute_as_a_filter_parameter_using_the_dot_notation:
NameError: uninitialized constant ActiveRecord::Encryption::ConfigurableTest::OpenStruct
test/cases/encryption/configurable_test.rb:45:in `block in <class:ConfigurableTest>'
```
Also change another anonymous block to a named block as requested by
skipkayhil, although it does not trigger the same error as the method
does not contain any keyword arguments.
Fix: https://github.com/rails/rails/issues/51386
This significantly reduce the depth of the tree for large `OR`
conditions. I was initially a bit on the fence about that fix,
but given that `And` is already implemented this way, I see no
reasons not to do the same.
Amusingly, the reported repro script now makes SQLite fail:
```ruby
SQLite3::SQLException: Expression tree is too large (maximum depth 1000)
```
Ref: https://github.com/rails/rails/pull/26103
Ref: https://github.com/rails/rails/pull/51426
A fairly common mistake with Rails is to enqueue a job from inside a
transaction, and a record as argumemnt, which then lead to a RecordNotFound
error when picked up by the queue.
This is even one of the arguments advanced for job runners backed by the
database such as `solid_queue`, `delayed_job` or `good_job`. But relying
on this is undesirable iin my opinion as it makes the Active Job abstraction
leaky, and if in the future you need to migrate to another backend or even
just move the queue to a separate database, you may experience a lot of race
conditions of the sort.
But more generally, being able to defer work to after the current transaction
has been a missing feature of Active Record. Right now the only way to do it
is from a model callback, and this forces moving things in Active Record
models that sometimes are better done elsewhere. Even as a self-proclaimed
"service object skeptic", I often wanted this capability over the last decade,
and I'm sure it got asked or desired by many more people.
Also there's some 3rd party gems adding this capability using monkey patches.
It's not a reason to upstream the capability, but it's a proof that there is
demand for it.
Implementation wise, this proof of concept shows that it's not really hard to
implement, even with nested multi-db transactions support.
Co-Authored-By: Cristian Bica <cristian.bica@gmail.com>
That is, if the reflection found is not valid, we don't want to emit the warning
because it's misleading. It says the inverse association could have been automatically
inferred but wasn't because `automatically_invert_plural_associations` is disabled.
However, this is not true, because later on, when we check whether the reflection
is valid, we see it's not, and end up returning `nil`.
We had to revert rails/rails@6dd1929 due to some regressions it caused. Here are some tests that would prevent those regressions in the future. See previous commits for more detail.
This reverts commit 6dd1929b04.
This introduced a change in behaviour since type_for_attribute is aware of custom types but lookup_cast_type does not.
Additionally, since we no longer to use the table and column info to get attributes, this introduced an issue where attribute types were not be correctly found for some queries, where we were joining a table that has a different name than the name of the reflection for that association.
This commit makes two types of queries retry-able by opting into our `allow_retry` flag:
1) SELECT queries we construct by walking the Arel tree via `#to_sql_and_binds`. We use a
new `retryable` attribute on collector classes, which defaults to true for most node types,
but will be set to false for non-idempotent node types (functions, SQL literals, etc). The
`retryable` value is returned from `#to_sql_and_binds` and used by `#select_all` and
passed down the call stack, eventually reaching the adapter's `#internal_exec_query` method.
Internally-generated SQL literals are marked as retryable via a new `retryable` attribute on
`Arel::Nodes::SqlLiteral`.
2) `#find` and `#find_by` queries with known attributes. We set `allow_retry: true` in `#cached_find_by`,
and pass this down to `#find_by_sql` and `#_query_by_sql`.
These changes ensure that queries we know are safe to retry can be retried automatically.
Some association options, e.g. `through`, were only added to
`.valid_options` list only if they were provided. It means that
sometimes ArgumentError's message would not mention all the
possible options.
Ref: https://github.com/rails/rails/pull/50284
While having the inverse association configured it generally positive
as it avoid some extra queries etc, infering it may break legecy code,
as evidenced by how it broke `ActiveStorage::Blob` in https://github.com/rails/rails/pull/50800
As such we can't just enable this behavior immediately, we need to provide
and upgrade path for users.