mirror of
https://github.com/github/rails.git
synced 2026-04-26 03:00:59 -04:00
Revert "Deprecate defining scopes with a callable (lambda, proc, etc) via the scope class method. Just define a class method yourself instead."
This reverts commit f0e198bfa1.
Conflicts:
activerecord/test/models/post.rb
This commit is contained in:
@@ -1,23 +1,5 @@
|
|||||||
*Rails 3.1.0 (unreleased)*
|
*Rails 3.1.0 (unreleased)*
|
||||||
|
|
||||||
* Passing a proc (or other object that responds to #call) to scope is deprecated. If you need your
|
|
||||||
scope to be lazily evaluated, or takes parameters, please define it as a normal class method
|
|
||||||
instead. For example, change this:
|
|
||||||
|
|
||||||
class Post < ActiveRecord::Base
|
|
||||||
scope :unpublished, lambda { where('published_at > ?', Time.now) }
|
|
||||||
end
|
|
||||||
|
|
||||||
To this:
|
|
||||||
|
|
||||||
class Post < ActiveRecord::Base
|
|
||||||
def self.unpublished
|
|
||||||
where('published_at > ?', Time.now)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
[Jon Leighton]
|
|
||||||
|
|
||||||
* Default scopes are now evaluated at the latest possible moment, to avoid problems where
|
* Default scopes are now evaluated at the latest possible moment, to avoid problems where
|
||||||
scopes would be created which would implicitly contain the default scope, which would then
|
scopes would be created which would implicitly contain the default scope, which would then
|
||||||
be impossible to get rid of via Model.unscoped.
|
be impossible to get rid of via Model.unscoped.
|
||||||
|
|||||||
@@ -51,14 +51,6 @@ module ActiveRecord
|
|||||||
# The above calls to <tt>scope</tt> define class methods Shirt.red and Shirt.dry_clean_only. Shirt.red,
|
# The above calls to <tt>scope</tt> define class methods Shirt.red and Shirt.dry_clean_only. Shirt.red,
|
||||||
# in effect, represents the query <tt>Shirt.where(:color => 'red')</tt>.
|
# in effect, represents the query <tt>Shirt.where(:color => 'red')</tt>.
|
||||||
#
|
#
|
||||||
# Note that this is simply 'syntactic sugar' for defining an actual class method:
|
|
||||||
#
|
|
||||||
# class Shirt < ActiveRecord::Base
|
|
||||||
# def self.red
|
|
||||||
# where(:color => 'red')
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# Unlike <tt>Shirt.find(...)</tt>, however, the object returned by Shirt.red is not an Array; it
|
# Unlike <tt>Shirt.find(...)</tt>, however, the object returned by Shirt.red is not an Array; it
|
||||||
# resembles the association object constructed by a <tt>has_many</tt> declaration. For instance,
|
# resembles the association object constructed by a <tt>has_many</tt> declaration. For instance,
|
||||||
# you can invoke <tt>Shirt.red.first</tt>, <tt>Shirt.red.count</tt>, <tt>Shirt.red.where(:size => 'small')</tt>.
|
# you can invoke <tt>Shirt.red.first</tt>, <tt>Shirt.red.count</tt>, <tt>Shirt.red.where(:size => 'small')</tt>.
|
||||||
@@ -82,34 +74,14 @@ module ActiveRecord
|
|||||||
# then <tt>elton.shirts.red.dry_clean_only</tt> will return all of Elton's red, dry clean
|
# then <tt>elton.shirts.red.dry_clean_only</tt> will return all of Elton's red, dry clean
|
||||||
# only shirts.
|
# only shirts.
|
||||||
#
|
#
|
||||||
# If you need to pass parameters to a scope, define it as a normal method:
|
# Named \scopes can also be procedural:
|
||||||
#
|
#
|
||||||
# class Shirt < ActiveRecord::Base
|
# class Shirt < ActiveRecord::Base
|
||||||
# def self.colored(color)
|
# scope :colored, lambda {|color| where(:color => color) }
|
||||||
# where(:color => color)
|
|
||||||
# end
|
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# In this example, <tt>Shirt.colored('puce')</tt> finds all puce shirts.
|
# In this example, <tt>Shirt.colored('puce')</tt> finds all puce shirts.
|
||||||
#
|
#
|
||||||
# Note that scopes defined with \scope will be evaluated when they are defined, rather than
|
|
||||||
# when they are used. For example, the following would be incorrect:
|
|
||||||
#
|
|
||||||
# class Post < ActiveRecord::Base
|
|
||||||
# scope :recent, where('published_at >= ?', Time.now - 1.week)
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# The example above would be 'frozen' to the <tt>Time.now</tt> value when the <tt>Post</tt>
|
|
||||||
# class was defined, and so the resultant SQL query would always be the same. The correct
|
|
||||||
# way to do this would be via a class method, which will re-evaluate the scope each time
|
|
||||||
# it is called:
|
|
||||||
#
|
|
||||||
# class Post < ActiveRecord::Base
|
|
||||||
# def self.recent
|
|
||||||
# where('published_at >= ?', Time.now - 1.week)
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# Named \scopes can also have extensions, just as with <tt>has_many</tt> declarations:
|
# Named \scopes can also have extensions, just as with <tt>has_many</tt> declarations:
|
||||||
#
|
#
|
||||||
# class Shirt < ActiveRecord::Base
|
# class Shirt < ActiveRecord::Base
|
||||||
@@ -120,18 +92,6 @@ module ActiveRecord
|
|||||||
# end
|
# end
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# The above could also be written as a class method like so:
|
|
||||||
#
|
|
||||||
# class Shirt < ActiveRecord::Base
|
|
||||||
# def self.red
|
|
||||||
# where(:color => 'red').extending do
|
|
||||||
# def dom_id
|
|
||||||
# 'red_shirts'
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
#
|
|
||||||
# Scopes can also be used while creating/building a record.
|
# Scopes can also be used while creating/building a record.
|
||||||
#
|
#
|
||||||
# class Article < ActiveRecord::Base
|
# class Article < ActiveRecord::Base
|
||||||
@@ -168,24 +128,6 @@ module ActiveRecord
|
|||||||
valid_scope_name?(name)
|
valid_scope_name?(name)
|
||||||
extension = Module.new(&Proc.new) if block_given?
|
extension = Module.new(&Proc.new) if block_given?
|
||||||
|
|
||||||
if !scope_options.is_a?(Relation) && scope_options.respond_to?(:call)
|
|
||||||
ActiveSupport::Deprecation.warn <<-WARN
|
|
||||||
Passing a proc (or other object that responds to #call) to scope is deprecated. If you need your scope to be lazily evaluated, or takes parameters, please define it as a normal class method instead. For example, change this:
|
|
||||||
|
|
||||||
class Post < ActiveRecord::Base
|
|
||||||
scope :unpublished, lambda { where('published_at > ?', Time.now) }
|
|
||||||
end
|
|
||||||
|
|
||||||
To this:
|
|
||||||
|
|
||||||
class Post < ActiveRecord::Base
|
|
||||||
def self.unpublished
|
|
||||||
where('published_at > ?', Time.now)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
WARN
|
|
||||||
end
|
|
||||||
|
|
||||||
scope_proc = lambda do |*args|
|
scope_proc = lambda do |*args|
|
||||||
options = scope_options.respond_to?(:call) ? scope_options.call(*args) : scope_options
|
options = scope_options.respond_to?(:call) ? scope_options.call(*args) : scope_options
|
||||||
options = scoped.apply_finder_options(options) if options.is_a?(Hash)
|
options = scoped.apply_finder_options(options) if options.is_a?(Hash)
|
||||||
|
|||||||
@@ -471,12 +471,6 @@ class NamedScopeTest < ActiveRecord::TestCase
|
|||||||
require "models/without_table"
|
require "models/without_table"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_scopes_with_callables_are_deprecated
|
|
||||||
assert_deprecated do
|
|
||||||
Post.scope :WE_SO_EXCITED, lambda { |partyingpartyingpartying, yeah| fun!.fun!.fun! }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
class DynamicScopeMatchTest < ActiveRecord::TestCase
|
class DynamicScopeMatchTest < ActiveRecord::TestCase
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
class Comment < ActiveRecord::Base
|
class Comment < ActiveRecord::Base
|
||||||
def self.limit_by(l)
|
scope :limit_by, lambda {|l| limit(l) }
|
||||||
limit(l)
|
|
||||||
end
|
|
||||||
|
|
||||||
scope :containing_the_letter_e, :conditions => "comments.body LIKE '%e%'"
|
scope :containing_the_letter_e, :conditions => "comments.body LIKE '%e%'"
|
||||||
scope :not_again, where("comments.body NOT LIKE '%again%'")
|
scope :not_again, where("comments.body NOT LIKE '%again%'")
|
||||||
scope :for_first_post, :conditions => { :post_id => 1 }
|
scope :for_first_post, :conditions => { :post_id => 1 }
|
||||||
|
|||||||
@@ -8,13 +8,12 @@ class Post < ActiveRecord::Base
|
|||||||
scope :containing_the_letter_a, where("body LIKE '%a%'")
|
scope :containing_the_letter_a, where("body LIKE '%a%'")
|
||||||
scope :ranked_by_comments, order("comments_count DESC")
|
scope :ranked_by_comments, order("comments_count DESC")
|
||||||
|
|
||||||
def self.limit_by(l)
|
scope :limit_by, lambda {|l| limit(l) }
|
||||||
limit(l)
|
scope :with_authors_at_address, lambda { |address| {
|
||||||
end
|
:conditions => [ 'authors.author_address_id = ?', address.id ],
|
||||||
|
:joins => 'JOIN authors ON authors.id = posts.author_id'
|
||||||
def self.with_authors_at_address(address)
|
}
|
||||||
where('authors.author_address_id = ?', address.id).joins('JOIN authors ON authors.id = posts.author_id')
|
}
|
||||||
end
|
|
||||||
|
|
||||||
belongs_to :author do
|
belongs_to :author do
|
||||||
def greeting
|
def greeting
|
||||||
@@ -29,10 +28,9 @@ class Post < ActiveRecord::Base
|
|||||||
|
|
||||||
scope :with_special_comments, :joins => :comments, :conditions => {:comments => {:type => 'SpecialComment'} }
|
scope :with_special_comments, :joins => :comments, :conditions => {:comments => {:type => 'SpecialComment'} }
|
||||||
scope :with_very_special_comments, joins(:comments).where(:comments => {:type => 'VerySpecialComment'})
|
scope :with_very_special_comments, joins(:comments).where(:comments => {:type => 'VerySpecialComment'})
|
||||||
|
scope :with_post, lambda {|post_id|
|
||||||
def self.with_post(post_id)
|
{ :joins => :comments, :conditions => {:comments => {:post_id => post_id} } }
|
||||||
joins(:comments).where(:comments => { :post_id => post_id })
|
}
|
||||||
end
|
|
||||||
|
|
||||||
has_many :comments do
|
has_many :comments do
|
||||||
def find_most_recent
|
def find_most_recent
|
||||||
|
|||||||
@@ -1,20 +1,10 @@
|
|||||||
class Topic < ActiveRecord::Base
|
class Topic < ActiveRecord::Base
|
||||||
scope :base
|
scope :base
|
||||||
|
scope :written_before, lambda { |time|
|
||||||
ActiveSupport::Deprecation.silence do
|
if time
|
||||||
scope :written_before, lambda { |time|
|
{ :conditions => ['written_on < ?', time] }
|
||||||
if time
|
end
|
||||||
{ :conditions => ['written_on < ?', time] }
|
}
|
||||||
end
|
|
||||||
}
|
|
||||||
|
|
||||||
scope :with_object, Class.new(Struct.new(:klass)) {
|
|
||||||
def call
|
|
||||||
klass.where(:approved => true)
|
|
||||||
end
|
|
||||||
}.new(self)
|
|
||||||
end
|
|
||||||
|
|
||||||
scope :approved, :conditions => {:approved => true}
|
scope :approved, :conditions => {:approved => true}
|
||||||
scope :rejected, :conditions => {:approved => false}
|
scope :rejected, :conditions => {:approved => false}
|
||||||
|
|
||||||
@@ -29,6 +19,12 @@ class Topic < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
scope :with_object, Class.new(Struct.new(:klass)) {
|
||||||
|
def call
|
||||||
|
klass.where(:approved => true)
|
||||||
|
end
|
||||||
|
}.new(self)
|
||||||
|
|
||||||
module NamedExtension
|
module NamedExtension
|
||||||
def two
|
def two
|
||||||
2
|
2
|
||||||
|
|||||||
Reference in New Issue
Block a user