Skip to content

Commit

Permalink
Add configurable deprecation warning for singular associations
Browse files Browse the repository at this point in the history
This removes the singularize from `where` which runs on all `expand_from_hash` keys which might be reflections or column names. This saves a lot of time by avoiding singularizing column names.

Previously in #45163 the singularize was removed entirely. after some reflection, I think it is better to at least give a warning for one release since `where` is a very popular API and the problems you can run into with incorrect relation could be hard to debug.

Configurable with `ActiveRecord::Base.allow_deprecated_singular_assocaitions_name = false` / `config.active_record.allow_deprecated_singular_assocaitions_name = false`
  • Loading branch information
HParker committed Jun 16, 2022
1 parent 8a52f9b commit 3a04c7b
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 1 deletion.
7 changes: 7 additions & 0 deletions activerecord/CHANGELOG.md
@@ -1,3 +1,10 @@
* Add configurable deprecation warning for singular associations

This adds a deprecation warning when using the plural name of a singular associations in `where`.
It is possible to opt into the new more performant behavior with `config.active_record.allow_deprecated_singular_associations_name = false`

*Adam Hess*

* Run transactional callbacks on the freshest instance to save a given
record within a transaction.

Expand Down
7 changes: 7 additions & 0 deletions activerecord/lib/active_record.rb
Expand Up @@ -336,6 +336,13 @@ def self.global_executor_concurrency # :nodoc:
singleton_class.attr_accessor :verify_foreign_keys_for_fixtures
self.verify_foreign_keys_for_fixtures = false

##
# :singleton-method:
# If true, Rails will continue allowing plural association names in where clauses on singular associations
# This behavior will be removed in Rails 7.2.
singleton_class.attr_accessor :allow_deprecated_singular_associations_name
self.allow_deprecated_singular_associations_name = true

singleton_class.attr_accessor :query_transformers
self.query_transformers = []

Expand Down
11 changes: 10 additions & 1 deletion activerecord/lib/active_record/table_metadata.rb
Expand Up @@ -23,7 +23,16 @@ def has_column?(column_name)
end

def associated_with?(table_name)
klass&._reflect_on_association(table_name)
if reflection = klass&._reflect_on_association(table_name)
reflection
elsif ActiveRecord.allow_deprecated_singular_associations_name && reflection = klass&._reflect_on_association(table_name.singularize)
ActiveSupport::Deprecation.warn(<<~MSG)
In Rails 7.2, referring to singular associations by their plural name will be deprecated.
To continue querying `#{table_name.singularize}` use `#{table_name}` instead.
You can get the new more performant behavior now by setting config.active_record.allow_deprecated_singular_associations_name = false
MSG
reflection
end
end

def associated_table(table_name)
Expand Down
21 changes: 21 additions & 0 deletions guides/source/configuring.md
Expand Up @@ -67,6 +67,8 @@ Below are the default values associated with each target version. In cases of co
- [`config.action_controller.allow_deprecated_parameters_hash_equality`](#config-action-controller-allow-deprecated-parameters-hash-equality): `false`
- [`config.log_file_size`](#config-log-file-size): `100.megabytes`
- [`config.active_record.sqlite3_adapter_strict_strings_by_default`](#config-active-record-sqlite3-adapter-strict-strings-by-default): `false`
- [`config.active_record.allow_deprecated_singular_associations_name`](#config-active-record-allow-deprecated-singular-associations-name): `true`


#### Default Values for Target Version 7.0

Expand Down Expand Up @@ -1027,6 +1029,25 @@ Defaults to `4`.
This number must be considered in accordance with the database pool size configured in `database.yml`. The connection pool
should be large enough to accommodate both the foreground threads (.e.g web server or job worker threads) and background threads.

#### `config.active_record.allow_deprecated_singular_associations_name`

This maintains the deprecated associations behavior where singular associations can be referred to in where clauses by their plural name. Enable this configuration option to opt into the new behavior.

before,

```ruby
class Post
self.table_name = "blog_posts"
end

class Comment
belongs_to :post
end

Comment.join(:post).where(posts: { id: 1 }) # deprecated if the table name is not `posts`
Comment.join(:post).where(post: { id: 1 }) # instead use the relation's name
```

#### `ActiveRecord::ConnectionAdapters::Mysql2Adapter.emulate_booleans`

Controls whether the Active Record MySQL adapter will consider all `tinyint(1)` columns as booleans. Defaults to `true`.
Expand Down
1 change: 1 addition & 0 deletions railties/lib/rails/application/configuration.rb
Expand Up @@ -264,6 +264,7 @@ def load_defaults(target_version)

if respond_to?(:active_record)
active_record.run_commit_callbacks_on_first_saved_instances_in_transaction = false
active_record.allow_deprecated_singular_associations_name = false
end

if respond_to?(:action_dispatch)
Expand Down
Expand Up @@ -44,3 +44,6 @@
# For example, it is possible to create an index for a non existing column.
# See https://www.sqlite.org/quirks.html#double_quoted_string_literals_are_accepted for more details.
# Rails.application.config.active_record.sqlite3_adapter_strict_strings_by_default = true

# Disable deprecated singular associations names
# Rails.application.config.active_record.allow_deprecated_singular_associations_name = true

0 comments on commit 3a04c7b

Please sign in to comment.