diff options
-rw-r--r-- | activerecord/CHANGELOG.md | 6 | ||||
-rw-r--r-- | activerecord/lib/active_record/scoping/default.rb | 3 | ||||
-rw-r--r-- | activerecord/test/cases/scoping/default_scoping_test.rb | 12 | ||||
-rw-r--r-- | activerecord/test/models/cat.rb | 13 | ||||
-rw-r--r-- | activerecord/test/schema/schema.rb | 5 |
5 files changed, 38 insertions, 1 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 83200c9f91..f854c106e8 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,9 @@ +* Execute default_scope defined by abstract class in the context of subclass. + + Fixes #23413 & #10658 + + *Mehmet Emin İNAÇ* + * Fix an issue when preloading associations with extensions. Previously every association with extension methods was transformed into an instance dependent scope. This is no longer the case. diff --git a/activerecord/lib/active_record/scoping/default.rb b/activerecord/lib/active_record/scoping/default.rb index f6b6768ce3..9eab59ac78 100644 --- a/activerecord/lib/active_record/scoping/default.rb +++ b/activerecord/lib/active_record/scoping/default.rb @@ -115,7 +115,8 @@ module ActiveRecord base_rel ||= relation evaluate_default_scope do default_scopes.inject(base_rel) do |default_scope, scope| - default_scope.merge(base_rel.scoping { scope.call }) + scope = scope.respond_to?(:to_proc) ? scope : scope.method(:call) + default_scope.merge(base_rel.instance_exec(&scope)) end end end diff --git a/activerecord/test/cases/scoping/default_scoping_test.rb b/activerecord/test/cases/scoping/default_scoping_test.rb index c918cbdef5..dcd09b6973 100644 --- a/activerecord/test/cases/scoping/default_scoping_test.rb +++ b/activerecord/test/cases/scoping/default_scoping_test.rb @@ -4,6 +4,7 @@ require 'models/comment' require 'models/developer' require 'models/computer' require 'models/vehicle' +require 'models/cat' class DefaultScopingTest < ActiveRecord::TestCase fixtures :developers, :posts, :comments @@ -485,4 +486,15 @@ class DefaultScopingTest < ActiveRecord::TestCase assert_equal 1, SubConditionalStiPost.all.to_a.size assert_equal 2, SubConditionalStiPost.unscope(where: :title).to_a.size end + + def test_with_abstract_class_scope_should_be_executed_in_correct_context + vegetarian_pattern, gender_pattern = if current_adapter?(:Mysql2Adapter) + [/`lions`.`is_vegetarian`/, /`lions`.`gender`/] + else + [/"lions"."is_vegetarian"/, /"lions"."gender"/] + end + + assert_match vegetarian_pattern, Lion.all.to_sql + assert_match gender_pattern, Lion.female.to_sql + end end diff --git a/activerecord/test/models/cat.rb b/activerecord/test/models/cat.rb new file mode 100644 index 0000000000..e543d3aadb --- /dev/null +++ b/activerecord/test/models/cat.rb @@ -0,0 +1,13 @@ +class Cat < ActiveRecord::Base + self.abstract_class = true + + enum gender: [:female, :male] + + scope :female, -> { where(gender: genders[:female]) } + scope :male, -> { where(gender: genders[:male]) } + + default_scope -> { where(is_vegetarian: false) } +end + +class Lion < Cat +end diff --git a/activerecord/test/schema/schema.rb b/activerecord/test/schema/schema.rb index 2a8996f35c..01dbf2cee6 100644 --- a/activerecord/test/schema/schema.rb +++ b/activerecord/test/schema/schema.rb @@ -421,6 +421,11 @@ ActiveRecord::Schema.define do t.integer :amount end + create_table :lions, force: true do |t| + t.integer :gender + t.boolean :is_vegetarian, default: false + end + create_table :lock_without_defaults, force: true do |t| t.column :lock_version, :integer end |