rails: Default scope is not overridden with scope for same attributes
Here is the failing test for this
diff --git a/activerecord/test/cases/scoping/default_scoping_test.rb b/activerecord/test/cases/scoping/default_scoping_test.rb
index 71754cf..2cf13c2 100644
--- a/activerecord/test/cases/scoping/default_scoping_test.rb
+++ b/activerecord/test/cases/scoping/default_scoping_test.rb
@@ -11,6 +11,11 @@ class DefaultScopingTest < ActiveRecord::TestCase
assert_equal expected, received
end
+ def test_scope_overrides_default_scope_for_same_attributes
+ assert_equal DeveloperCalledJamis.where(name: 'David'), DeveloperCalledJamis.unscoped.where(name: 'David')
+ assert_equal DeveloperCalledJamis.david, DeveloperCalledJamis.unscoped.david
+ end
+
def test_default_scope_as_class_method
assert_equal [developers(:david).becomes(ClassMethodDeveloperCalledDavid)], ClassMethodDeveloperCalledDavid.all
end
diff --git a/activerecord/test/models/developer.rb b/activerecord/test/models/developer.rb
index 2e2d8a0..ae9c8e8 100644
--- a/activerecord/test/models/developer.rb
+++ b/activerecord/test/models/developer.rb
@@ -165,6 +165,7 @@ class DeveloperCalledJamis < ActiveRecord::Base
default_scope { where(:name => 'Jamis') }
scope :poor, -> { where('salary < 150000') }
+ scope :david, -> { where(:name => 'David') }
end
I found that this commit has broken this feature.https://github.com/rails/rails/commit/94924dc32baf78f13e289172534c2e71c9c8cade
before this commit these tests are working fine.
Issue linked #13870
About this issue
- Original URL
- State: closed
- Created 10 years ago
- Comments: 17 (17 by maintainers)
Commits related to this issue
- Revert "Simplify/fix implementation of default scopes" This reverts commit 94924dc32baf78f13e289172534c2e71c9c8cade. Conflicts: activerecord/lib/active_record/associations/association.rb activerec... — committed to rafaelfranca/omg-rails by rafaelfranca 10 years ago
- Add tests for default scope behaviour change See #13875 — committed to rails/rails by jonleighton 10 years ago
- Add tests for default scope behaviour change See #13875 — committed to rails/rails by jonleighton 10 years ago
Hi all,
Ok, I’ve had a think about this. It raises quite a complex set of issues but I’ll try to be as clear as possible.
The basic reason that this issue has come up is that before 94924dc32baf78f13e289172534c2e71c9c8cade, default scopes were treated in a “special” way in AR which required code in all sorts of places to treat default scopes slightly differently. The aim of that commit was to simplify our implementation by removing the special treatment: now default scopes are basically just a way of redefining the output of
MyModel.all
.Therefore, I’m pretty reluctant to revert 94924dc32baf78f13e289172534c2e71c9c8cade, as it makes our code quite a bit simpler, and also corrects some inherent flaws in our previous implementation of default scopes (i.e. the issue with
#except
mentioned in the commit message).So, let’s assume we won’t revert 94924dc32baf78f13e289172534c2e71c9c8cade, and look at options for correcting the behaviour change presented here.
First, let’s take this assertion:
(@raysrashmi, I’ve reordered the argument as
assert_equal
expects the ‘expected’ value to come first - this makes test failure messages read correctly.)So, if we accept that there shouldn’t be special handling for default scopes, we can say that the following is an equally valid assertion about the behaviour desired above:
But to implement this would directly contradict #7365 (which is already released in Rails 4.0). Therefore I don’t think it’s possible to make this “work” as specified by the test.
Let’s take a look at the second assertion (arguments again reordered for clarity):
It’s more realistic to be able to make this work, since we have control over the definition of the
david
method (inlib/active_record/scoping/named.rb
). One thing we could do to make it pass is this:However that unfortunately means that
Topic.rejected.approved == Topic.approved
, which again causes a regression from the behaviour implemented by #7365.So a more nuanced thing to do would be something like:
That would make our assertion pass:
But unfortunately the following would fail:
So such a change would create inconsistency; not a great thing in my opinion. So I don’t think it’s really feasible to “fix” the behaviour to satisfy this assertion either.
In conclusion I think we have basically two options:
I favour the second option. I basically think that we should document that people who want this sort of functionality should change this:
To this:
That’s also more explicit in my opinion as well.