Deprecated support for passing hashes and relations to default_scope, in favour of defining a 'default_scope' class method in the model. See the CHANGELOG for more details.

This commit is contained in:
Jon Leighton 2011-04-04 00:07:45 +01:00 committed by Aaron Patterson
parent fc9a04b6a6
commit 5740d4ec0c
17 changed files with 430 additions and 192 deletions

@ -1,5 +1,26 @@
*Rails 3.1.0 (unreleased)*
* Deprecated support for passing hashes and relations to 'default_scope'. Please create a class
method for your scope instead. For example, change this:
class Post < ActiveRecord::Base
default_scope where(:published => true)
end
To this:
class Post < ActiveRecord::Base
def self.default_scope
where(:published => true)
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.
* ConnectionManagement middleware is changed to clean up the connection pool

@ -425,8 +425,8 @@ class Base
self.store_full_sti_class = true
# Stores the default scope for the class
class_attribute :default_scoping, :instance_writer => false
self.default_scoping = []
class_attribute :default_scopes, :instance_writer => false
self.default_scopes = []
# Returns a hash of all the attributes that have been specified for serialization as
# keys and their class restriction as values.
@ -870,7 +870,9 @@ def arel_engine
# Returns a scope for this class without taking into account the default_scope.
#
# class Post < ActiveRecord::Base
# default_scope :published => true
# def self.default_scope
# where :published => true
# end
# end
#
# Post.all # Fires "SELECT * FROM posts WHERE published = true"
@ -892,13 +894,8 @@ def unscoped #:nodoc:
block_given? ? relation.scoping { yield } : relation
end
def scoped_methods #:nodoc:
key = :"#{self}_scoped_methods"
Thread.current[key] = Thread.current[key].presence || self.default_scoping.dup
end
def before_remove_const #:nodoc:
reset_scoped_methods
self.current_scope = nil
end
# Specifies how the record is loaded by +Marshal+.
@ -1020,7 +1017,7 @@ def method_missing(method_id, *arguments, &block)
super unless all_attributes_exists?(attribute_names)
if match.finder?
options = arguments.extract_options!
relation = options.any? ? construct_finder_arel(options, current_scoped_methods) : scoped
relation = options.any? ? scoped(options) : scoped
relation.send :find_by_attributes, match, attribute_names, *arguments
elsif match.instantiator?
scoped.send :find_or_instantiator_by_attributes, match, attribute_names, *arguments, &block
@ -1109,43 +1106,48 @@ def all_attributes_exists?(attribute_names)
# end
#
# *Note*: the +:find+ scope also has effect on update and deletion methods, like +update_all+ and +delete_all+.
def with_scope(method_scoping = {}, action = :merge, &block)
method_scoping = method_scoping.method_scoping if method_scoping.respond_to?(:method_scoping)
def with_scope(scope = {}, action = :merge, &block)
# If another Active Record class has been passed in, get its current scope
scope = scope.current_scope if !scope.is_a?(Relation) && scope.respond_to?(:current_scope)
if method_scoping.is_a?(Hash)
# Cannot use self.current_scope, because that could trigger build_default_scope, which
# could in turn result in with_scope being called and hence an infinite loop.
previous_scope = Thread.current[:"#{self}_current_scope"]
if scope.is_a?(Hash)
# Dup first and second level of hash (method and params).
method_scoping = method_scoping.dup
method_scoping.each do |method, params|
method_scoping[method] = params.dup unless params == true
scope = scope.dup
scope.each do |method, params|
scope[method] = params.dup unless params == true
end
method_scoping.assert_valid_keys([ :find, :create ])
relation = construct_finder_arel(method_scoping[:find] || {})
scope.assert_valid_keys([ :find, :create ])
relation = construct_finder_arel(scope[:find] || {})
if current_scoped_methods && current_scoped_methods.create_with_value && method_scoping[:create]
if previous_scope && previous_scope.create_with_value && scope[:create]
scope_for_create = if action == :merge
current_scoped_methods.create_with_value.merge(method_scoping[:create])
previous_scope.create_with_value.merge(scope[:create])
else
method_scoping[:create]
scope[:create]
end
relation = relation.create_with(scope_for_create)
else
scope_for_create = method_scoping[:create]
scope_for_create ||= current_scoped_methods.create_with_value if current_scoped_methods
scope_for_create = scope[:create]
scope_for_create ||= previous_scope.create_with_value if previous_scope
relation = relation.create_with(scope_for_create) if scope_for_create
end
method_scoping = relation
scope = relation
end
method_scoping = current_scoped_methods.merge(method_scoping) if current_scoped_methods && action == :merge
scope = previous_scope.merge(scope) if previous_scope && action == :merge
self.scoped_methods << method_scoping
self.current_scope = scope
begin
yield
ensure
self.scoped_methods.pop
self.current_scope = previous_scope
end
end
@ -1168,41 +1170,84 @@ def with_exclusive_scope(method_scoping = {}, &block)
with_scope(method_scoping, :overwrite, &block)
end
# Sets the default options for the model. The format of the
# <tt>options</tt> argument is the same as in find.
def current_scope #:nodoc:
Thread.current[:"#{self}_current_scope"] ||= build_default_scope
end
def current_scope=(scope) #:nodoc:
Thread.current[:"#{self}_current_scope"] = scope
end
# Implement this method 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
# end
#
# Person.all # => SELECT * FROM people ORDER BY last_name, first_name
#
# The <tt>default_scope</tt> is also applied while creating/building a record. It is not
# applied while updating a record.
#
# class Article < ActiveRecord::Base
# def self.default_scope
# where(:published => true)
# end
# end
#
# Article.new.published # => true
# Article.create.published # => true
#
# === Deprecation warning
#
# There is an alternative syntax as follows:
#
# class Person < ActiveRecord::Base
# default_scope order('last_name, first_name')
# end
#
# <tt>default_scope</tt> is also applied while creating/building a record. It is not
# applied while updating a record.
#
# class Article < ActiveRecord::Base
# default_scope where(:published => true)
# end
#
# Article.new.published # => true
# Article.create.published # => true
def default_scope(options = {})
reset_scoped_methods
default_scoping = self.default_scoping.dup
self.default_scoping = default_scoping << construct_finder_arel(options, default_scoping.pop)
# 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:
class Post < ActiveRecord::Base
default_scope where(:published => true)
end
To this:
class Post < ActiveRecord::Base
def self.default_scope
where(:published => true)
end
end
WARN
# Reset the current scope as it may contain scopes based on a now-invalid default scope
self.current_scope = nil
self.default_scopes = default_scopes.dup << scope
end
def current_scoped_methods #:nodoc:
method = scoped_methods.last
if method.respond_to?(:call)
relation.scoping { method.call }
else
method
def build_default_scope #:nodoc:
if method(:default_scope).owner != Base.singleton_class
# Exclusively scope to just the relation, to avoid infinite recursion where the
# default scope tries to use the default scope tries to use the default scope...
relation.scoping { default_scope }
elsif default_scopes.any?
default_scopes.inject(relation) do |default_scope, scope|
if scope.is_a?(Hash)
default_scope.apply_finder_options(scope)
else
default_scope.merge(scope)
end
end
end
end
def reset_scoped_methods #:nodoc:
Thread.current[:"#{self}_scoped_methods"] = nil
end
# Returns the class type of the record using the current module as a prefix. So descendants of
# MyApp::Business::Account would appear as MyApp::Business::AccountSubclass.
def compute_type(type_name)
@ -1916,11 +1961,8 @@ def convert_number_column_value(value)
end
def populate_with_current_scope_attributes
if scope = self.class.send(:current_scoped_methods)
create_with = scope.scope_for_create
create_with.each { |att,value|
respond_to?("#{att}=") && send("#{att}=", value)
}
self.class.scoped.scope_for_create.each do |att,value|
respond_to?("#{att}=") && send("#{att}=", value)
end
end

@ -35,7 +35,7 @@ def scoped(options = nil)
if options
scoped.apply_finder_options(options)
else
current_scoped_methods ? relation.merge(current_scoped_methods) : relation.clone
(current_scope || relation).clone
end
end

@ -154,12 +154,7 @@ def many?
# Please check unscoped if you want to remove all previous scopes (including
# the default_scope) during the execution of a block.
def scoping
@klass.scoped_methods << self
begin
yield
ensure
@klass.scoped_methods.pop
end
@klass.send(:with_scope, self, :overwrite) { yield }
end
# Updates all records with details given if they match a set of conditions supplied, limits and order can

@ -70,16 +70,16 @@ def test_create_from_association_should_respect_default_scope
# would be convenient), because this would cause that scope to be applied to any callbacks etc.
def test_build_and_create_should_not_happen_within_scope
car = cars(:honda)
original_scoped_methods = Bulb.scoped_methods
scoped_count = car.foo_bulbs.scoped.where_values.count
bulb = car.bulbs.build
assert_equal original_scoped_methods, bulb.scoped_methods_after_initialize
bulb = car.foo_bulbs.build
assert_not_equal scoped_count, bulb.scope_after_initialize.where_values.count
bulb = car.bulbs.create
assert_equal original_scoped_methods, bulb.scoped_methods_after_initialize
bulb = car.foo_bulbs.create
assert_not_equal scoped_count, bulb.scope_after_initialize.where_values.count
bulb = car.bulbs.create!
assert_equal original_scoped_methods, bulb.scoped_methods_after_initialize
bulb = car.foo_bulbs.create!
assert_not_equal scoped_count, bulb.scope_after_initialize.where_values.count
end
def test_no_sql_should_be_fired_if_association_already_loaded

@ -165,16 +165,16 @@ def test_successful_build_association
def test_build_and_create_should_not_happen_within_scope
pirate = pirates(:blackbeard)
original_scoped_methods = Bulb.scoped_methods.dup
scoped_count = pirate.association(:foo_bulb).scoped.where_values.count
bulb = pirate.build_bulb
assert_equal original_scoped_methods, bulb.scoped_methods_after_initialize
bulb = pirate.build_foo_bulb
assert_not_equal scoped_count, bulb.scope_after_initialize.where_values.count
bulb = pirate.create_bulb
assert_equal original_scoped_methods, bulb.scoped_methods_after_initialize
bulb = pirate.create_foo_bulb
assert_not_equal scoped_count, bulb.scope_after_initialize.where_values.count
bulb = pirate.create_bulb!
assert_equal original_scoped_methods, bulb.scoped_methods_after_initialize
bulb = pirate.create_foo_bulb!
assert_not_equal scoped_count, bulb.scope_after_initialize.where_values.count
end
def test_create_association

@ -1630,14 +1630,18 @@ def test_default_scope_is_reset
Object.const_set :UnloadablePost, Class.new(ActiveRecord::Base)
UnloadablePost.table_name = 'posts'
UnloadablePost.class_eval do
default_scope order('posts.comments_count ASC')
class << self
def default_scope
order('posts.comments_count ASC')
end
end
end
UnloadablePost.scoped_methods # make Thread.current[:UnloadablePost_scoped_methods] not nil
UnloadablePost.scoped # make Thread.current[:UnloadablePost_scoped_methods] not nil
UnloadablePost.unloadable
assert_not_nil Thread.current[:UnloadablePost_scoped_methods]
assert_not_nil Thread.current[:UnloadablePost_current_scope]
ActiveSupport::Dependencies.remove_unloadable_constants!
assert_nil Thread.current[:UnloadablePost_scoped_methods]
assert_nil Thread.current[:UnloadablePost_current_scope]
ensure
Object.class_eval{ remove_const :UnloadablePost } if defined?(UnloadablePost)
end

@ -249,22 +249,21 @@ def test_immutable_scope
end
def test_scoped_with_duck_typing
scoping = Struct.new(:method_scoping).new(:find => { :conditions => ["name = ?", 'David'] })
scoping = Struct.new(:current_scope).new(:find => { :conditions => ["name = ?", 'David'] })
Developer.send(:with_scope, scoping) do
assert_equal %w(David), Developer.find(:all).map { |d| d.name }
end
end
def test_ensure_that_method_scoping_is_correctly_restored
scoped_methods = Developer.instance_eval('current_scoped_methods')
begin
Developer.send(:with_scope, :find => { :conditions => "name = 'Jamis'" }) do
raise "an exception"
end
rescue
end
assert_equal scoped_methods, Developer.instance_eval('current_scoped_methods')
assert !Developer.scoped.where_values.include?("name = 'Jamis'")
end
end
@ -509,14 +508,15 @@ def test_immutable_merged_scope
def test_ensure_that_method_scoping_is_correctly_restored
Developer.send(:with_scope, :find => { :conditions => "name = 'David'" }) do
scoped_methods = Developer.instance_eval('current_scoped_methods')
begin
Developer.send(:with_scope, :find => { :conditions => "name = 'Maiha'" }) do
raise "an exception"
end
rescue
end
assert_equal scoped_methods, Developer.instance_eval('current_scoped_methods')
assert Developer.scoped.where_values.include?("name = 'David'")
assert !Developer.scoped.where_values.include?("name = 'Maiha'")
end
end

@ -132,8 +132,6 @@ def test_scoped_create_with_create_with_has_higher_priority
end
def test_ensure_that_method_scoping_is_correctly_restored
scoped_methods = Developer.send(:current_scoped_methods)
begin
Developer.where("name = 'Jamis'").scoping do
raise "an exception"
@ -141,7 +139,7 @@ def test_ensure_that_method_scoping_is_correctly_restored
rescue
end
assert_equal scoped_methods, Developer.send(:current_scoped_methods)
assert !Developer.scoped.where_values.include?("name = 'Jamis'")
end
end
@ -310,35 +308,6 @@ def test_default_scope
assert_equal expected, received
end
def test_default_scope_with_lambda
expected = Post.find_all_by_author_id(2)
PostForAuthor.selected_author = 2
received = PostForAuthor.all
assert_equal expected, received
expected = Post.find_all_by_author_id(1)
PostForAuthor.selected_author = 1
received = PostForAuthor.all
assert_equal expected, received
end
def test_default_scope_with_thing_that_responds_to_call
klass = Class.new(ActiveRecord::Base) do
self.table_name = 'posts'
end
klass.class_eval do
default_scope Class.new(Struct.new(:klass)) {
def call
klass.where(:author_id => 2)
end
}.new(self)
end
records = klass.all
assert_equal 3, records.length
assert_equal 2, records.first.author_id
end
def test_default_scope_is_unscoped_on_find
assert_equal 1, DeveloperCalledDavid.count
assert_equal 11, DeveloperCalledDavid.unscoped.count
@ -364,49 +333,10 @@ def test_default_scoping_with_threads
end
end
def test_default_scoping_with_inheritance
# Inherit a class having a default scope and define a new default scope
klass = Class.new(DeveloperOrderedBySalary)
klass.send :default_scope, :limit => 1
# Scopes added on children should append to parent scope
assert_equal 1, klass.scoped.limit_value
assert_equal ['salary DESC'], klass.scoped.order_values
# Parent should still have the original scope
assert_nil DeveloperOrderedBySalary.scoped.limit_value
assert_equal ['salary DESC'], DeveloperOrderedBySalary.scoped.order_values
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)
klass.__send__ :default_scope, :conditions => { :name => "David" }
klass.__send__ :default_scope, :conditions => { :salary => 100000 }
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)
klass.class_eval do
default_scope where("name = 'David'")
default_scope where("salary = 100000")
end
assert_equal 1, klass.count
assert_equal "David", klass.first.name
assert_equal 100000, klass.first.salary
def test_default_scope_with_inheritance
wheres = InheritedPoorDeveloperCalledJamis.scoped.where_values_hash
assert_equal "Jamis", wheres[:name]
assert_equal 50000, wheres[:salary]
end
def test_method_scope
@ -449,12 +379,6 @@ def test_order_in_default_scope_should_prevail
assert_equal expected, received
end
def test_default_scope_using_relation
posts = PostWithComment.scoped
assert_equal 2, posts.count
assert_equal posts(:thinking), posts.first
end
def test_create_attribute_overwrites_default_scoping
assert_equal 'David', PoorDeveloperCalledJamis.create!(:name => 'David').name
assert_equal 200000, PoorDeveloperCalledJamis.create!(:name => 'David', :salary => 200000).salary
@ -504,3 +428,176 @@ def test_create_with_reset
assert_equal 'Jamis', jamis.name
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_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_equal ['salary DESC'], DeprecatedDeveloperOrderedBySalary.scoped.order_values }.join
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 1, klass.scoped.limit_value
assert_equal ['salary DESC'], klass.scoped.order_values
# Parent should still have the original scope
assert_nil DeprecatedDeveloperOrderedBySalary.scoped.limit_value
assert_equal ['salary DESC'], DeprecatedDeveloperOrderedBySalary.scoped.order_values
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 }
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
end
end

@ -1,14 +1,15 @@
class Bulb < ActiveRecord::Base
default_scope :conditions => {:name => 'defaulty' }
def self.default_scope
where :name => 'defaulty'
end
belongs_to :car
attr_reader :scoped_methods_after_initialize
attr_reader :scope_after_initialize
after_initialize :record_scoped_methods_after_initialize
def record_scoped_methods_after_initialize
@scoped_methods_after_initialize = self.class.scoped_methods.dup
after_initialize :record_scope_after_initialize
def record_scope_after_initialize
@scope_after_initialize = self.class.scoped
end
end

@ -1,6 +1,7 @@
class Car < ActiveRecord::Base
has_many :bulbs
has_many :foo_bulbs, :class_name => "Bulb", :conditions => { :name => 'foo' }
has_many :tyres
has_many :engines
has_many :wheels, :as => :wheelable
@ -14,9 +15,13 @@ class Car < ActiveRecord::Base
end
class CoolCar < Car
default_scope :order => 'name desc'
def self.default_scope
order 'name desc'
end
end
class FastCar < Car
default_scope order('name desc')
def self.default_scope
order 'name desc'
end
end

@ -13,7 +13,9 @@ class Categorization < ActiveRecord::Base
class SpecialCategorization < ActiveRecord::Base
self.table_name = 'categorizations'
default_scope where(:special => true)
def self.default_scope
where(:special => true)
end
belongs_to :author
belongs_to :category

@ -86,7 +86,11 @@ def raise_if_projects_empty!
class DeveloperOrderedBySalary < ActiveRecord::Base
self.table_name = 'developers'
default_scope :order => 'salary DESC'
def self.default_scope
order('salary DESC')
end
scope :by_name, order('name DESC')
def self.all_ordered_by_name
@ -98,15 +102,72 @@ def self.all_ordered_by_name
class DeveloperCalledDavid < ActiveRecord::Base
self.table_name = 'developers'
default_scope :conditions => "name = 'David'"
def self.default_scope
where "name = 'David'"
end
end
class DeveloperCalledJamis < ActiveRecord::Base
self.table_name = 'developers'
default_scope :conditions => { :name => 'Jamis' }
def self.default_scope
where :name => 'Jamis'
end
end
class AbstractDeveloperCalledJamis < ActiveRecord::Base
self.abstract_class = true
def self.default_scope
where :name => 'Jamis'
end
end
class PoorDeveloperCalledJamis < ActiveRecord::Base
self.table_name = 'developers'
default_scope :conditions => { :name => 'Jamis', :salary => 50000 }
def self.default_scope
where :name => 'Jamis', :salary => 50000
end
end
class InheritedPoorDeveloperCalledJamis < DeveloperCalledJamis
self.table_name = 'developers'
def self.default_scope
super.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 DeprecatedPoorDeveloperCalledJamis < ActiveRecord::Base
self.table_name = 'developers'
default_scope :conditions => { :name => 'Jamis', :salary => 50000 }
end
end

@ -34,7 +34,7 @@ class Pirate < ActiveRecord::Base
:after_remove => proc {|p,b| p.ship_log << "after_removing_proc_bird_#{b.id}"}
has_many :birds_with_reject_all_blank, :class_name => "Bird"
has_one :bulb, :foreign_key => :car_id
has_one :foo_bulb, :foreign_key => :car_id, :class_name => "Bulb", :conditions => { :name => 'foo' }
accepts_nested_attributes_for :parrots, :birds, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? }
accepts_nested_attributes_for :ship, :allow_destroy => true, :reject_if => proc { |attributes| attributes.empty? }

@ -142,20 +142,25 @@ class SubStiPost < StiPost
self.table_name = Post.table_name
end
class PostWithComment < ActiveRecord::Base
self.table_name = 'posts'
default_scope where("posts.comments_count > 0").order("posts.comments_count ASC")
ActiveSupport::Deprecation.silence do
class DeprecatedPostWithComment < ActiveRecord::Base
self.table_name = 'posts'
default_scope where("posts.comments_count > 0").order("posts.comments_count ASC")
end
end
class PostForAuthor < ActiveRecord::Base
self.table_name = 'posts'
cattr_accessor :selected_author
default_scope lambda { where(:author_id => PostForAuthor.selected_author) }
end
class FirstPost < ActiveRecord::Base
self.table_name = 'posts'
default_scope where(:id => 1)
def self.default_scope
where(:id => 1)
end
has_many :comments, :foreign_key => :post_id
has_one :comment, :foreign_key => :post_id
end

@ -18,6 +18,9 @@ def make_comments
end
class BadReference < ActiveRecord::Base
self.table_name ='references'
default_scope :conditions => {:favourite => false }
self.table_name = 'references'
def self.default_scope
where :favourite => false
end
end

@ -1,3 +1,5 @@
class WithoutTable < ActiveRecord::Base
default_scope where(:published => true)
end
def self.default_scope
where(:published => true)
end
end