今天看了一点关于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.