今天看了一点关于with_scope的知识,有点感觉,写点东西
with_scope 与 named_scope 没有关系,named_scope 是依赖于with_scope工作的。
1、with_scope
with_scope是给一个model添加一个scope来扩展功能
def self.all_male
with_scope(:find => {:conditions => "gender = 'm'"}) do
all_active
end
end
def self.all_active
with_scope(:find => {:conditions => "status = 'active'"}) do
find(:first)
end
end
# User.all_active
# SELECT * FROM "users" WHERE (status = 'active') LIMIT 1
# User.all_male
# SELECT * FROM "users" WHERE ((gender = 'm') AND (status = 'active')) LIMIT 1
named_scope就是运用with_scope的这种特性来将多个name_scope形成一个query
2、学习编写自己的named_scope
module ActiveRecord
module MynamedScope
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def mynamed_scope(name,options = {})
puts "name is #{name}"
end
end
end
end
ActiveRecord::Base.send(:include, ActiveRecord::MynamedScope)
class User < ActiveRecord::Base
mynamed_scope :active, :conditions => {:status => 'active'}
mynamed_scope :male, :conditions => {:gender => 'm'}
end
我们就可以通过
User.active
User.male
User.active.male
User.male.active
得到正确的返回结果。
最后结果
module ActiveRecord
module MynamedScope
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def myscopes
read_inheritable_attribute(:myscopes) || write_inheritable_attribute(:myscopes, {})
end
def mynamed_scope(name,options = {})
name = name.to_sym
myscopes[name] = lambda { |proxy_scope| Scope.new(proxy_scope,options) }
(class << self; self end).instance_eval do
define_method name do
myscopes[name].call(self)
end
end
end
class Scope
attr_reader :proxy_scope, :proxy_options
delegate :with_scope, :to => :proxy_scope
def initialize(proxy_scope, options)
@proxy_scope, @proxy_options = proxy_scope, options
end
def inspect
load_found
end
def load_found
find(:all)
end
def method_missing(method, *args, &block)
if proxy_scope.myscopes.include?(method)
proxy_scope.myscopes[method].call(self)
else
with_scope :find => proxy_options do
proxy_scope.send(method,*args)
end
end
end
end # end of class Scope
end # end of module ClassMethods
end # endof module MynamedScope
end
ActiveRecord::Base.send(:include, ActiveRecord::MynamedScope)
class User < ActiveRecord::Base
mynamed_scope :active, :conditions => {:status => 'active'}
mynamed_scope :male, :conditions => {:gender => 'm'}
end
原文章参考地址:http://www.neeraj.name/blog/articles/751-under-the-hood-how-named_scope-works
文章二、
It looks like Nick Kallen’s wildly popular has_finder plugin will be making its way into Rails 2.x in the form of named_scope
. Observe:
All the goodness you’ve come to love in has_finder
is now available as named_scope
– plus you get some extra goodies too. User.all
is given to you for free as an alias for User.find(:all)
.
class User < ActiveRecord::Base
named_scope :active, :conditions => {:active => true}
named_scope :inactive, :conditions => {:active => false}
named_scope :recent, lambda { { :conditions => ['created_at > ?', 1.week.ago] } }
end
# Standard usage
User.active # same as User.find(:all, :conditions => {:active => true})
User.inactive # same as User.find(:all, :conditions => {:active => false})
User.recent # same as User.find(:all, :conditions => ['created_at > ?', 1.week.ago])
# They're nest-able too!
User.active.recent
# same as:
# User.with_scope(:conditions => {:active => true}) do
# User.find(:all, :conditions => ['created_at > ?', 1.week.ago])
# end
Advanced
For those with more discriminating needs, don’t forget some of these has_finder
tidbits:
Passing Arguments
Pass in arguments to your named scopes to specify conditions (or other props) at run-time.
class User < ActiveRecord::Base
named_scope :registered, lambda { |time_ago| { :conditions => ['created_at > ?', time_ago] }
end
User.registered 7.days.ago # same as User.find(:all, :conditions => ['created_at > ?', 7.days.ago])
Named Scope Extensions
Extend named scopes (in a similar fashion to association extensions ).
class User < ActiveRecord::Base
named_scope :inactive, :conditions => {:active => false} do
def activate
each { |i| i.update_attribute(:active, true) }
end
end
end
# Re-activate all inactive users
User.inactive.activate
Anonymous Scopes
You can also pass around scopes as first class objects using scoped
(a named scoped provided to you for free) as a way to build hairy queries on the fly.
# Store named scopes
active = User.scoped(:conditions => {:active => true})
recent = User.scoped(:conditions => ['created_at > ?', 7.days.ago])
# Which can be combined
recent_active = recent.active
# And operated upon
recent_active.each { |u| ... }
named_scope
is a truly great feature. If you haven’t started using it yet, do so. You won’t know how you lived without it. Major thanks goes out to Nick.