aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/scoping/named.rb
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record/scoping/named.rb')
-rw-r--r--activerecord/lib/active_record/scoping/named.rb113
1 files changed, 48 insertions, 65 deletions
diff --git a/activerecord/lib/active_record/scoping/named.rb b/activerecord/lib/active_record/scoping/named.rb
index 75f31229b5..fb5f5b5be0 100644
--- a/activerecord/lib/active_record/scoping/named.rb
+++ b/activerecord/lib/active_record/scoping/named.rb
@@ -3,7 +3,7 @@ require 'active_support/core_ext/hash/except'
require 'active_support/core_ext/kernel/singleton_class'
module ActiveRecord
- # = Active Record Named \Scopes
+ # = Active Record \Named \Scopes
module Scoping
module Named
extend ActiveSupport::Concern
@@ -16,11 +16,11 @@ module ActiveRecord
# posts.each {|p| puts p.name } # Fires "select * from posts" and loads post objects
#
# fruits = Fruit.all
- # fruits = fruits.where(:color => 'red') if options[:red_only]
+ # fruits = fruits.where(color: 'red') if options[:red_only]
# fruits = fruits.limit(10) if limited?
#
- # You can define a \scope that applies to all finders using
- # ActiveRecord::Base.default_scope.
+ # You can define a scope that applies to all finders using
+ # <tt>ActiveRecord::Base.default_scope</tt>.
def all
if current_scope
current_scope.clone
@@ -31,7 +31,6 @@ module ActiveRecord
end
end
- ##
# Collects attributes from scopes that should be applied when creating
# an AR instance for the particular class this is called on.
def scope_attributes # :nodoc:
@@ -44,86 +43,70 @@ module ActiveRecord
end
end
- ##
# Are there default attributes associated with this scope?
def scope_attributes? # :nodoc:
current_scope || default_scopes.any?
end
- # Adds a class method for retrieving and querying objects. A \scope represents a narrowing of a database query,
- # such as <tt>where(:color => :red).select('shirts.*').includes(:washing_instructions)</tt>.
+ # Adds a class method for retrieving and querying objects. A \scope
+ # represents a narrowing of a database query, such as
+ # <tt>where(color: :red).select('shirts.*').includes(:washing_instructions)</tt>.
#
# class Shirt < ActiveRecord::Base
- # scope :red, where(:color => 'red')
- # scope :dry_clean_only, joins(:washing_instructions).where('washing_instructions.dry_clean_only = ?', true)
+ # scope :red, -> { where(color: 'red') }
+ # scope :dry_clean_only, -> { joins(:washing_instructions).where('washing_instructions.dry_clean_only = ?', true) }
# end
#
- # 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>.
+ # The above calls to +scope+ define class methods <tt>Shirt.red</tt> and
+ # <tt>Shirt.dry_clean_only</tt>. <tt>Shirt.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:
+ # You should always pass a callable object to the scopes defined
+ # with +scope+. This ensures that the scope is re-evaluated each
+ # time it is called.
+ #
+ # Note that this is simply 'syntactic sugar' for defining an actual
+ # class method:
#
# class Shirt < ActiveRecord::Base
# def self.red
- # where(:color => 'red')
+ # where(color: 'red')
# end
# end
#
- # 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,
- # you can invoke <tt>Shirt.red.first</tt>, <tt>Shirt.red.count</tt>, <tt>Shirt.red.where(:size => 'small')</tt>.
- # Also, just as with the association objects, named \scopes act like an Array, implementing Enumerable;
- # <tt>Shirt.red.each(&block)</tt>, <tt>Shirt.red.first</tt>, and <tt>Shirt.red.inject(memo, &block)</tt>
- # all behave as if Shirt.red really was an Array.
- #
- # These named \scopes are composable. For instance, <tt>Shirt.red.dry_clean_only</tt> will produce
- # all shirts that are both red and dry clean only.
- # Nested finds and calculations also work with these compositions: <tt>Shirt.red.dry_clean_only.count</tt>
- # returns the number of garments for which these criteria obtain. Similarly with
- # <tt>Shirt.red.dry_clean_only.average(:thread_count)</tt>.
- #
- # All \scopes are available as class methods on the ActiveRecord::Base descendant upon which
- # the \scopes were defined. But they are also available to <tt>has_many</tt> associations. If,
+ # Unlike <tt>Shirt.find(...)</tt>, however, the object returned by
+ # <tt>Shirt.red</tt> is not an Array; it resembles the association object
+ # constructed by a +has_many+ declaration. For instance, you can invoke
+ # <tt>Shirt.red.first</tt>, <tt>Shirt.red.count</tt>,
+ # <tt>Shirt.red.where(size: 'small')</tt>. Also, just as with the
+ # association objects, named \scopes act like an Array, implementing
+ # Enumerable; <tt>Shirt.red.each(&block)</tt>, <tt>Shirt.red.first</tt>,
+ # and <tt>Shirt.red.inject(memo, &block)</tt> all behave as if
+ # <tt>Shirt.red</tt> really was an Array.
+ #
+ # These named \scopes are composable. For instance,
+ # <tt>Shirt.red.dry_clean_only</tt> will produce all shirts that are
+ # both red and dry clean only. Nested finds and calculations also work
+ # with these compositions: <tt>Shirt.red.dry_clean_only.count</tt>
+ # returns the number of garments for which these criteria obtain.
+ # Similarly with <tt>Shirt.red.dry_clean_only.average(:thread_count)</tt>.
+ #
+ # All scopes are available as class methods on the ActiveRecord::Base
+ # descendant upon which the \scopes were defined. But they are also
+ # available to +has_many+ associations. If,
#
# class Person < ActiveRecord::Base
# has_many :shirts
# end
#
- # then <tt>elton.shirts.red.dry_clean_only</tt> will return all of Elton's red, dry clean
- # only shirts.
- #
- # Named \scopes can also be procedural:
- #
- # class Shirt < ActiveRecord::Base
- # scope :colored, lambda { |color| where(:color => color) }
- # end
- #
- # In this example, <tt>Shirt.colored('puce')</tt> finds all puce shirts.
- #
- # On Ruby 1.9 you can use the 'stabby lambda' syntax:
- #
- # scope :colored, ->(color) { where(:color => color) }
- #
- # 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.current - 1.week)
- # end
- #
- # The example above would be 'frozen' to the <tt>Time.current</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 lambda, which will re-evaluate the scope each time
- # it is called:
- #
- # class Post < ActiveRecord::Base
- # scope :recent, lambda { where('published_at >= ?', Time.current - 1.week) }
- # end
+ # then <tt>elton.shirts.red.dry_clean_only</tt> will return all of
+ # Elton's red, dry clean only shirts.
#
- # Named \scopes can also have extensions, just as with <tt>has_many</tt> declarations:
+ # \Named scopes can also have extensions, just as with +has_many+
+ # declarations:
#
# class Shirt < ActiveRecord::Base
- # scope :red, where(:color => 'red') do
+ # scope :red, -> { where(color: 'red') } do
# def dom_id
# 'red_shirts'
# end
@@ -133,18 +116,18 @@ module ActiveRecord
# Scopes can also be used while creating/building a record.
#
# class Article < ActiveRecord::Base
- # scope :published, where(:published => true)
+ # scope :published, -> { where(published: true) }
# end
#
# Article.published.new.published # => true
# Article.published.create.published # => true
#
- # Class methods on your model are automatically available
+ # \Class methods on your model are automatically available
# on scopes. Assuming the following setup:
#
# class Article < ActiveRecord::Base
- # scope :published, where(:published => true)
- # scope :featured, where(:featured => true)
+ # scope :published, -> { where(published: true) }
+ # scope :featured, -> { where(featured: true) }
#
# def self.latest_article
# order('published_at desc').first