New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make the Relation -> Model delegation stricter #50396
base: main
Are you sure you want to change the base?
Conversation
323e59a
to
d3990e8
Compare
d3990e8
to
189e334
Compare
0fe6cde
to
5c84152
Compare
Note to self:
|
:sanitize_sql_like, :unscoped, to: :klass | ||
|
||
# TODO: scoped delegate | ||
[:find_signed, :find_signed!, :delete, :find_by_token_for, :find_by_token_for!, :upsert_all, :insert_all, :insert_all!].each do |method| |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This list is very likely incomplete.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I rebased, and this is still the main blocker. We have a number of ActiveRecord::Base
class methods that rely on this scoped delegation.
I need to find a good alternative.
Makes sense |
perhaps relevant: #50760 |
Fix: rails#51775 This us us being bitten by rails#50396 once more. We should really make this delegation much stricter.
Got bit by this again: #51776, I really need to finish this PR somehow. |
8127973
to
fcde614
Compare
Ref: rails#50396 Ref: rails#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 rails#51775 I'm planning to restrict this automatic delegation to methods defined in childs of `ActiveRecord::Base` only: rails#50396 but for this to work we must first refactor any Rails code that rely on it.
Ref: rails#50396 Ref: rails#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 rails#51775 I'm planning to restrict this automatic delegation to methods defined in childs of `ActiveRecord::Base` only: rails#50396 but for this to work we must first refactor any Rails code that rely on it.
Ref: rails#50396 Ref: rails#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 rails#51775 I'm planning to restrict this automatic delegation to methods defined in childs of `ActiveRecord::Base` only: rails#50396 but for this to work we must first refactor any Rails code that rely on it.
Ref: rails#50396 Ref: rails#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 rails#51775 I'm planning to restrict this automatic delegation to methods defined in childs of `ActiveRecord::Base` only: rails#50396 but for this to work we must first refactor any Rails code that rely on it.
Ref: rails#50396 Ref: rails#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 rails#51775 I'm planning to restrict this automatic delegation to methods defined in childs of `ActiveRecord::Base` only: rails#50396 but for this to work we must first refactor any Rails code that rely on it.
fcde614
to
9c09de8
Compare
activerecord/test/cases/associations/has_and_belongs_to_many_associations_test.rb
Outdated
Show resolved
Hide resolved
Ref: rails#50396 As well as related methods.
53b00de
to
c28d7a9
Compare
In rails#50395 I noticed lots of methods are delegated from `Relation` to the model. The intent of this code is to allow using use defined class methods like scopes. But because of this autmated delegation it allowed calling any `ActiveRecord::Base` class method on a `Relation`, which in itself may be desireable, however we very wastefully define the delegator on the first call, and worse we wrap it with a current scope setter. So I think we should be more strict about it.
c28d7a9
to
f7c6343
Compare
@@ -100,7 +100,7 @@ def #{method}(...) | |||
:to_sentence, :to_fs, :to_formatted_s, :as_json, | |||
:shuffle, :split, :slice, :index, :rindex, to: :records | |||
|
|||
delegate :primary_key, :lease_connection, :connection, :with_connection, :transaction, to: :klass | |||
delegate :primary_key, :with_connection, :connection, :table_name, :transaction, :sanitize_sql_like, :unscoped, to: :klass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not quite sure whether we should keep any of these.
Fix: rails#51775 This us us being bitten by rails#50396 once more. We should really make this delegation much stricter.
Ref: rails#50396 Ref: rails#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 rails#51775 I'm planning to restrict this automatic delegation to methods defined in childs of `ActiveRecord::Base` only: rails#50396 but for this to work we must first refactor any Rails code that rely on it.
Ref: rails#50396 Ref: rails#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 rails#51775 I'm planning to restrict this automatic delegation to methods defined in childs of `ActiveRecord::Base` only: rails#50396 but for this to work we must first refactor any Rails code that rely on it.
Ref: rails#50396 As well as related methods.
I slept on this one. I think long term we should deprecate most of these delegations, but short term we can simply make it so that we still delegate for methods present in I also want to ship the call site cleanup part. |
Ref: #50396 Ref: #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 #51775 I'm planning to restrict this automatic delegation to methods defined in childs of `ActiveRecord::Base` only: #50396 but for this to work we must first refactor any Rails code that rely on it.
Ref: #50396 Ref: #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 #51775 I'm planning to restrict this automatic delegation to methods defined in childs of `ActiveRecord::Base` only: #50396 but for this to work we must first refactor any Rails code that rely on it.
Ref: #50396 As well as related methods.
In #50395 I noticed lots of methods are delegated from
Relation
to the model. The intent of this code is to allow using use defined class methods like scopes.But because of this autmated delegation it allowed calling any
ActiveRecord::Base
class method on aRelation
, which in itself may be desireable, however we very wastefully define the delegator on the first call, and worse we wrap it with a current scope setter.So I think we should be more strict about it.
NB: this of course breaks a tons of test, so I need to find more time to finish this, and it likely need a config flag and a deprecation notice of some sort. Or alternatively we can just accept this API, but delegate all the
AR::Base
class methods eagerly and without the scoping overhead. TBD.