aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord
diff options
context:
space:
mode:
authorJon Leighton <j@jonathanleighton.com>2011-04-18 23:15:38 +0100
committerJon Leighton <j@jonathanleighton.com>2011-04-18 23:15:38 +0100
commit6f84c73dc48538202766cff3d973a53d3c30848e (patch)
treeb95728dfe8813ad3637fbe3a1e52c9207279663d /activerecord
parent0acc6bd6cb1d27fdbb0c00ac3a322bc8413e03cc (diff)
downloadrails-6f84c73dc48538202766cff3d973a53d3c30848e.tar.gz
rails-6f84c73dc48538202766cff3d973a53d3c30848e.tar.bz2
rails-6f84c73dc48538202766cff3d973a53d3c30848e.zip
Un-deprecate using 'default_scope' as a macro, but if you are calling the macro multiple times that will give deprecation warnings, and in 3.2 we will simply overwrite the default scope when you call the macro multiple times.
Diffstat (limited to 'activerecord')
-rw-r--r--activerecord/CHANGELOG27
-rw-r--r--activerecord/lib/active_record/base.rb47
-rw-r--r--activerecord/test/cases/relation_scoping_test.rb181
-rw-r--r--activerecord/test/models/bulb.rb5
-rw-r--r--activerecord/test/models/car.rb8
-rw-r--r--activerecord/test/models/categorization.rb5
-rw-r--r--activerecord/test/models/developer.rb68
-rw-r--r--activerecord/test/models/post.rb5
-rw-r--r--activerecord/test/models/reference.rb5
-rw-r--r--activerecord/test/models/without_table.rb4
10 files changed, 85 insertions, 270 deletions
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index 6b3d408720..4ae82a6419 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -11,25 +11,34 @@
[Jon Leighton]
-* Deprecated support for passing hashes and relations to 'default_scope'. Please create a class
- method for your scope instead. For example, change this:
+* Calling 'default_scope' multiple times in a class (including when a superclass calls
+ 'default_scope') is deprecated. The current behavior is that this will merge the default
+ scopes together:
- class Post < ActiveRecord::Base
+ class Post < ActiveRecord::Base # Rails 3.1
+ default_scope where(:published => true)
+ default_scope where(:hidden => false)
+ # The default scope is now: where(:published => true, :hidden => false)
+ end
+
+ In Rails 3.2, the behavior will be changed to overwrite previous scopes:
+
+ class Post < ActiveRecord::Base # Rails 3.2
default_scope where(:published => true)
+ default_scope where(:hidden => false)
+ # The default scope is now: where(:hidden => false)
end
- To this:
+ If you wish to merge default scopes in special ways, it is recommended to define your default
+ scope as a class method and use the standard techniques for sharing code (inheritance, mixins,
+ etc.):
class Post < ActiveRecord::Base
def self.default_scope
- where(:published => true)
+ where(:published => true).where(:hidden => false)
end
end
- Rationale: It will make the implementation simpler because we can simply use inheritance to
- handle inheritance scenarios, rather than trying to make up our own rules about what should
- happen when you call default_scope multiple times or in subclasses.
-
[Jon Leighton]
* PostgreSQL adapter only supports PostgreSQL version 8.2 and higher.
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 08a41e2d8b..5b316c17be 100644
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -1177,13 +1177,11 @@ MSG
Thread.current[:"#{self}_current_scope"] = scope
end
- # Implement this method in your model to set a default scope for all operations on
+ # Use this macro in your model to set a default scope for all operations on
# the model.
#
# class Person < ActiveRecord::Base
- # def self.default_scope
- # order('last_name, first_name')
- # end
+ # default_scope order('last_name, first_name')
# end
#
# Person.all # => SELECT * FROM people ORDER BY last_name, first_name
@@ -1192,39 +1190,48 @@ MSG
# applied while updating a record.
#
# class Article < ActiveRecord::Base
- # def self.default_scope
- # where(:published => true)
- # end
+ # default_scope where(:published => true)
# end
#
# Article.new.published # => true
# Article.create.published # => true
#
- # === Deprecation warning
+ # If you need to do more complex things with a default scope, you can alternatively
+ # define it as a class method:
#
- # There is an alternative syntax as follows:
- #
- # class Person < ActiveRecord::Base
- # default_scope order('last_name, first_name')
+ # class Article < ActiveRecord::Base
+ # def self.default_scope
+ # # Should return a scope, you can call 'super' here etc.
+ # end
# end
- #
- # This is now deprecated and will be removed in Rails 3.2.
def default_scope(scope = {})
- ActiveSupport::Deprecation.warn <<-WARN
-Passing a hash or scope to default_scope is deprecated and will be removed in Rails 3.2. You should create a class method for your scope instead. For example, change this:
+ if default_scopes.length != 0
+ ActiveSupport::Deprecation.warn <<-WARN
+Calling 'default_scope' multiple times in a class (including when a superclass calls 'default_scope') is deprecated. The current behavior is that this will merge the default scopes together:
-class Post < ActiveRecord::Base
+class Post < ActiveRecord::Base # Rails 3.1
default_scope where(:published => true)
+ default_scope where(:hidden => false)
+ # The default scope is now: where(:published => true, :hidden => false)
end
-To this:
+In Rails 3.2, the behavior will be changed to overwrite previous scopes:
+
+class Post < ActiveRecord::Base # Rails 3.2
+ default_scope where(:published => true)
+ default_scope where(:hidden => false)
+ # The default scope is now: where(:hidden => false)
+end
+
+If you wish to merge default scopes in special ways, it is recommended to define your default scope as a class method and use the standard techniques for sharing code (inheritance, mixins, etc.):
class Post < ActiveRecord::Base
def self.default_scope
- where(:published => true)
+ where(:published => true).where(:hidden => false)
end
end
-WARN
+ WARN
+ end
self.default_scopes = default_scopes.dup << scope
end
diff --git a/activerecord/test/cases/relation_scoping_test.rb b/activerecord/test/cases/relation_scoping_test.rb
index 5079aec9ba..e231371cf8 100644
--- a/activerecord/test/cases/relation_scoping_test.rb
+++ b/activerecord/test/cases/relation_scoping_test.rb
@@ -308,6 +308,10 @@ class DefaultScopingTest < ActiveRecord::TestCase
assert_equal expected, received
end
+ def test_default_scope_as_class_method
+ assert_equal [developers(:david).becomes(ClassMethodDeveloperCalledDavid)], ClassMethodDeveloperCalledDavid.all
+ end
+
def test_default_scope_is_unscoped_on_find
assert_equal 1, DeveloperCalledDavid.count
assert_equal 11, DeveloperCalledDavid.unscoped.count
@@ -339,6 +343,12 @@ class DefaultScopingTest < ActiveRecord::TestCase
assert_equal 50000, wheres[:salary]
end
+ def test_default_scope_with_multiple_calls
+ wheres = MultiplePoorDeveloperCalledJamis.scoped.where_values_hash
+ assert_equal "Jamis", wheres[:name]
+ assert_equal 50000, wheres[:salary]
+ end
+
def test_method_scope
expected = Developer.find(:all, :order => 'salary DESC, name DESC').collect { |dev| dev.salary }
received = DeveloperOrderedBySalary.all_ordered_by_name.collect { |dev| dev.salary }
@@ -434,175 +444,18 @@ class DefaultScopingTest < ActiveRecord::TestCase
assert DeveloperCalledJamis.unscoped.poor.include?(developers(:david).becomes(DeveloperCalledJamis))
assert_equal 10, DeveloperCalledJamis.unscoped.poor.length
end
-end
-
-class DeprecatedDefaultScopingTest < ActiveRecord::TestCase
- fixtures :developers, :posts
-
- def test_default_scope
- expected = Developer.find(:all, :order => 'salary DESC').collect { |dev| dev.salary }
- received = DeprecatedDeveloperOrderedBySalary.find(:all).collect { |dev| dev.salary }
- assert_equal expected, received
- end
- def test_default_scope_is_unscoped_on_find
- assert_equal 1, DeprecatedDeveloperCalledDavid.count
- assert_equal 11, DeprecatedDeveloperCalledDavid.unscoped.count
- end
+ def test_multiple_default_scope_calls_are_deprecated
+ klass = Class.new(ActiveRecord::Base)
- def test_default_scope_is_unscoped_on_create
- assert_nil DeprecatedDeveloperCalledJamis.unscoped.create!.name
- end
-
- def test_default_scope_with_conditions_string
- assert_equal Developer.find_all_by_name('David').map(&:id).sort, DeprecatedDeveloperCalledDavid.find(:all).map(&:id).sort
- assert_equal nil, DeprecatedDeveloperCalledDavid.create!.name
- end
-
- def test_default_scope_with_conditions_hash
- assert_equal Developer.find_all_by_name('Jamis').map(&:id).sort, DeprecatedDeveloperCalledJamis.find(:all).map(&:id).sort
- assert_equal 'Jamis', DeprecatedDeveloperCalledJamis.create!.name
- end
-
- def test_default_scoping_with_threads
- 2.times do
- Thread.new { assert DeprecatedDeveloperOrderedBySalary.scoped.to_sql.include?('salary DESC') }.join
+ assert_not_deprecated do
+ klass.send(:default_scope, :foo => :bar)
end
- end
-
- def test_default_scoping_with_inheritance
- # Inherit a class having a default scope and define a new default scope
- klass = Class.new(DeprecatedDeveloperOrderedBySalary)
- ActiveSupport::Deprecation.silence { klass.send :default_scope, :limit => 1 }
-
- # Scopes added on children should append to parent scope
- assert_equal [developers(:jamis).id], klass.all.map(&:id)
-
- # Parent should still have the original scope
- assert_equal Developer.order('salary DESC').map(&:id), DeprecatedDeveloperOrderedBySalary.all.map(&:id)
- end
-
- def test_default_scope_called_twice_merges_conditions
- Developer.destroy_all
- Developer.create!(:name => "David", :salary => 80000)
- Developer.create!(:name => "David", :salary => 100000)
- Developer.create!(:name => "Brian", :salary => 100000)
- klass = Class.new(Developer)
- ActiveSupport::Deprecation.silence do
- klass.__send__ :default_scope, :conditions => { :name => "David" }
- klass.__send__ :default_scope, :conditions => { :salary => 100000 }
+ assert_deprecated do
+ klass.send(:default_scope, :foo => :bar)
end
- assert_equal 1, klass.count
- assert_equal "David", klass.first.name
- assert_equal 100000, klass.first.salary
- end
-
- def test_default_scope_called_twice_in_different_place_merges_where_clause
- Developer.destroy_all
- Developer.create!(:name => "David", :salary => 80000)
- Developer.create!(:name => "David", :salary => 100000)
- Developer.create!(:name => "Brian", :salary => 100000)
-
- klass = Class.new(Developer)
- ActiveSupport::Deprecation.silence do
- klass.class_eval do
- default_scope where("name = 'David'")
- default_scope where("salary = 100000")
- end
- end
-
- assert_equal 1, klass.count
- assert_equal "David", klass.first.name
- assert_equal 100000, klass.first.salary
- end
- def test_method_scope
- expected = Developer.find(:all, :order => 'salary DESC, name DESC').collect { |dev| dev.salary }
- received = DeprecatedDeveloperOrderedBySalary.all_ordered_by_name.collect { |dev| dev.salary }
- assert_equal expected, received
- end
-
- def test_nested_scope
- expected = Developer.find(:all, :order => 'salary DESC, name DESC').collect { |dev| dev.salary }
- received = DeprecatedDeveloperOrderedBySalary.send(:with_scope, :find => { :order => 'name DESC'}) do
- DeprecatedDeveloperOrderedBySalary.find(:all).collect { |dev| dev.salary }
- end
- assert_equal expected, received
- end
-
- def test_scope_overwrites_default
- expected = Developer.find(:all, :order => 'salary DESC, name DESC').collect { |dev| dev.name }
- received = DeprecatedDeveloperOrderedBySalary.by_name.find(:all).collect { |dev| dev.name }
- assert_equal expected, received
- end
-
- def test_reorder_overrides_default_scope_order
- expected = Developer.order('name DESC').collect { |dev| dev.name }
- received = DeprecatedDeveloperOrderedBySalary.reorder('name DESC').collect { |dev| dev.name }
- assert_equal expected, received
- end
-
- def test_nested_exclusive_scope
- expected = Developer.find(:all, :limit => 100).collect { |dev| dev.salary }
- received = DeprecatedDeveloperOrderedBySalary.send(:with_exclusive_scope, :find => { :limit => 100 }) do
- DeprecatedDeveloperOrderedBySalary.find(:all).collect { |dev| dev.salary }
- end
- assert_equal expected, received
- end
-
- def test_order_in_default_scope_should_prevail
- expected = Developer.find(:all, :order => 'salary desc').collect { |dev| dev.salary }
- received = DeprecatedDeveloperOrderedBySalary.find(:all, :order => 'salary').collect { |dev| dev.salary }
- assert_equal expected, received
- end
-
- def test_default_scope_using_relation
- posts = DeprecatedPostWithComment.scoped
- assert_equal 2, posts.to_a.length
- assert_equal posts(:thinking), posts.first
- end
-
- def test_create_attribute_overwrites_default_scoping
- assert_equal 'David', DeprecatedPoorDeveloperCalledJamis.create!(:name => 'David').name
- assert_equal 200000, DeprecatedPoorDeveloperCalledJamis.create!(:name => 'David', :salary => 200000).salary
- end
-
- def test_create_attribute_overwrites_default_values
- assert_equal nil, DeprecatedPoorDeveloperCalledJamis.create!(:salary => nil).salary
- assert_equal 50000, DeprecatedPoorDeveloperCalledJamis.create!(:name => 'David').salary
- end
-
- def test_default_scope_attribute
- jamis = DeprecatedPoorDeveloperCalledJamis.new(:name => 'David')
- assert_equal 50000, jamis.salary
- end
-
- def test_where_attribute
- aaron = DeprecatedPoorDeveloperCalledJamis.where(:salary => 20).new(:name => 'Aaron')
- assert_equal 20, aaron.salary
- assert_equal 'Aaron', aaron.name
- end
-
- def test_where_attribute_merge
- aaron = DeprecatedPoorDeveloperCalledJamis.where(:name => 'foo').new(:name => 'Aaron')
- assert_equal 'Aaron', aaron.name
- end
-
- def test_create_with_merge
- aaron = DeprecatedPoorDeveloperCalledJamis.create_with(:name => 'foo', :salary => 20).merge(
- DeprecatedPoorDeveloperCalledJamis.create_with(:name => 'Aaron')).new
- assert_equal 20, aaron.salary
- assert_equal 'Aaron', aaron.name
-
- aaron = DeprecatedPoorDeveloperCalledJamis.create_with(:name => 'foo', :salary => 20).
- create_with(:name => 'Aaron').new
- assert_equal 20, aaron.salary
- assert_equal 'Aaron', aaron.name
- end
-
- def test_create_with_reset
- jamis = DeprecatedPoorDeveloperCalledJamis.create_with(:name => 'Aaron').create_with(nil).new
- assert_equal 'Jamis', jamis.name
+ assert_equal 2, klass.default_scopes.length
end
end
diff --git a/activerecord/test/models/bulb.rb b/activerecord/test/models/bulb.rb
index 89ee5416bf..c68d008c26 100644
--- a/activerecord/test/models/bulb.rb
+++ b/activerecord/test/models/bulb.rb
@@ -1,8 +1,5 @@
class Bulb < ActiveRecord::Base
- def self.default_scope
- where :name => 'defaulty'
- end
-
+ default_scope where(:name => 'defaulty')
belongs_to :car
attr_reader :scope_after_initialize
diff --git a/activerecord/test/models/car.rb b/activerecord/test/models/car.rb
index a978debb58..b036f0f5c9 100644
--- a/activerecord/test/models/car.rb
+++ b/activerecord/test/models/car.rb
@@ -15,13 +15,9 @@ class Car < ActiveRecord::Base
end
class CoolCar < Car
- def self.default_scope
- order 'name desc'
- end
+ default_scope :order => 'name desc'
end
class FastCar < Car
- def self.default_scope
- order 'name desc'
- end
+ default_scope :order => 'name desc'
end
diff --git a/activerecord/test/models/categorization.rb b/activerecord/test/models/categorization.rb
index 39441e8610..4bd980e606 100644
--- a/activerecord/test/models/categorization.rb
+++ b/activerecord/test/models/categorization.rb
@@ -12,10 +12,7 @@ end
class SpecialCategorization < ActiveRecord::Base
self.table_name = 'categorizations'
-
- def self.default_scope
- where(:special => true)
- end
+ default_scope where(:special => true)
belongs_to :author
belongs_to :category
diff --git a/activerecord/test/models/developer.rb b/activerecord/test/models/developer.rb
index 10385ba899..93363f47c5 100644
--- a/activerecord/test/models/developer.rb
+++ b/activerecord/test/models/developer.rb
@@ -86,10 +86,7 @@ end
class DeveloperOrderedBySalary < ActiveRecord::Base
self.table_name = 'developers'
-
- def self.default_scope
- order('salary DESC')
- end
+ default_scope :order => 'salary DESC'
scope :by_name, order('name DESC')
@@ -102,74 +99,41 @@ end
class DeveloperCalledDavid < ActiveRecord::Base
self.table_name = 'developers'
-
- def self.default_scope
- where "name = 'David'"
- end
+ default_scope where("name = 'David'")
end
-class DeveloperCalledJamis < ActiveRecord::Base
+class ClassMethodDeveloperCalledDavid < ActiveRecord::Base
self.table_name = 'developers'
def self.default_scope
- where :name => 'Jamis'
+ where(:name => 'David')
end
-
- scope :poor, where('salary < 150000')
end
-class AbstractDeveloperCalledJamis < ActiveRecord::Base
- self.abstract_class = true
-
- def self.default_scope
- where :name => 'Jamis'
- end
+class DeveloperCalledJamis < ActiveRecord::Base
+ self.table_name = 'developers'
+ default_scope where(:name => 'Jamis')
+ scope :poor, where('salary < 150000')
end
class PoorDeveloperCalledJamis < ActiveRecord::Base
self.table_name = 'developers'
-
- def self.default_scope
- where :name => 'Jamis', :salary => 50000
- end
+ default_scope where(:name => 'Jamis', :salary => 50000)
end
class InheritedPoorDeveloperCalledJamis < DeveloperCalledJamis
self.table_name = 'developers'
- def self.default_scope
- super.where :salary => 50000
+ ActiveSupport::Deprecation.silence do
+ default_scope where(:salary => 50000)
end
end
-ActiveSupport::Deprecation.silence do
- class DeprecatedDeveloperOrderedBySalary < ActiveRecord::Base
- self.table_name = 'developers'
- default_scope :order => 'salary DESC'
-
- def self.by_name
- order('name DESC')
- end
-
- def self.all_ordered_by_name
- with_scope(:find => { :order => 'name DESC' }) do
- find(:all)
- end
- end
- end
-
- class DeprecatedDeveloperCalledDavid < ActiveRecord::Base
- self.table_name = 'developers'
- default_scope :conditions => "name = 'David'"
- end
-
- class DeprecatedDeveloperCalledJamis < ActiveRecord::Base
- self.table_name = 'developers'
- default_scope :conditions => { :name => 'Jamis' }
- end
+class MultiplePoorDeveloperCalledJamis < ActiveRecord::Base
+ self.table_name = 'developers'
+ default_scope where(:name => 'Jamis')
- class DeprecatedPoorDeveloperCalledJamis < ActiveRecord::Base
- self.table_name = 'developers'
- default_scope :conditions => { :name => 'Jamis', :salary => 50000 }
+ ActiveSupport::Deprecation.silence do
+ default_scope where(:salary => 50000)
end
end
diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb
index 34cea60053..80296032bb 100644
--- a/activerecord/test/models/post.rb
+++ b/activerecord/test/models/post.rb
@@ -157,10 +157,7 @@ end
class FirstPost < ActiveRecord::Base
self.table_name = 'posts'
-
- def self.default_scope
- where(:id => 1)
- end
+ default_scope where(:id => 1)
has_many :comments, :foreign_key => :post_id
has_one :comment, :foreign_key => :post_id
diff --git a/activerecord/test/models/reference.rb b/activerecord/test/models/reference.rb
index 76c0a1a32e..c5af0b5d5f 100644
--- a/activerecord/test/models/reference.rb
+++ b/activerecord/test/models/reference.rb
@@ -19,8 +19,5 @@ end
class BadReference < ActiveRecord::Base
self.table_name = 'references'
-
- def self.default_scope
- where :favourite => false
- end
+ default_scope where(:favourite => false)
end
diff --git a/activerecord/test/models/without_table.rb b/activerecord/test/models/without_table.rb
index 1a63d6ceb6..184ab1649e 100644
--- a/activerecord/test/models/without_table.rb
+++ b/activerecord/test/models/without_table.rb
@@ -1,5 +1,3 @@
class WithoutTable < ActiveRecord::Base
- def self.default_scope
- where(:published => true)
- end
+ default_scope where(:published => true)
end