Rails源码阅读(五)with_scope 和 named_scope

Rails源码阅读(四)with_scope and named_scope

 

with_scope的用法

简而言之,with_scope的用法类似于with_options,能够在内层方法调用的时候,插入外层的条件。有点也类似,可以节省代码。with_scope的作用要多于with_options,这个在named_scope中就会看见了。

    这个例子可以看见,外层的查询条件加入了内层的查询条件中,起到了联合查询的目的。

  class Article < ActiveRecord::Base
    def self.find_with_scope
      with_scope(:find => { :conditions => "blog_id = 1", :limit => 1 }, :create => { :blog_id => 1 }) do
        with_scope(:find => { :limit => 10 })
          find(:all) # => SELECT * from articles WHERE blog_id = 1 LIMIT 10
        end
        with_scope(:find => { :conditions => "author_id = 3" })
          find(:all) # => SELECT * from articles WHERE blog_id = 1 AND author_id = 3 LIMIT 1
        end
      end
    end
  end

with_scopde是怎么实现的,代码研究

with_scope的源码比较长,就不粘贴了。

with_scope是个protected方法,实现过程是把参数保存在scope中,等最后查询(find)的时候,再取出scope中保存的条件来,加入find查询的条件中,起到了联合查询的作用。

见find的源码:

        def construct_finder_sql(options)
          scope = scope(:find)
          sql  = "SELECT #{options[:select] || (scope && scope[:select]) || default_select(options[:joins] || (scope && scope[:joins]))} "
          sql << "FROM #{options[:from]  || (scope && scope[:from]) || quoted_table_name} "

          add_joins!(sql, options[:joins], scope)
          add_conditions!(sql, options[:conditions], scope)

          add_group!(sql, options[:group], options[:having], scope)
          add_order!(sql, options[:order], scope)
          add_limit!(sql, options, scope)
          add_lock!(sql, options, scope)

          sql
        end

scope 有个技巧,当前要存入scope的条件存入了当前线程的hash中,并且名字为当前的类名相关。

这个是不是很像Hibernate中使用的ThreadLocal阿~

        def scoped_methods #:nodoc:
          Thread.current[:"#{self}_scoped_methods"] ||= self.default_scoping.dup #self.default_scoping = []
        end

另外注意,scoped_methods不会一直增长下去,而是用完就删除了!

          self.scoped_methods << method_scoping
          begin
            yield #查询
          ensure
            self.scoped_methods.pop #查询完了,就删除了
          end
 

举个例子:

 

class Tag < ActiveRecord::Base
  named_scope :red, :conditions => "id <= 10" do
    def dom_id
      'red_shirts'
    end
  end
  with_scope(:find => {:conditions => "id <= 5"}) do
    with_scope(:find => {:conditions => "id <= 4"}) do #用了两次哦!
      find(:all)
    end
  end
end

 

 这样在使用Tag.red的时候,跟踪下变量:

 

####这个是with_options存储的,可以看见,条件叠加了,都存储了下来

hash={:find=>{:conditions=>"(id <= 5) AND (id <= 4)"}}

####

####scope中存储的

scoped_methods=[{:find=>{:conditions=>"id <= 5"}}, nil]

####

 

 

 

参考:

http://muyu.iteye.com/blog/248400

http://xf986321.iteye.com/blog/413332

 

 

待续

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值