诗歌rails之with_scope(method_scoping = {}, action = :merge) {|| ...}
with_scope后面可以跟一个hash {方法名=>参数hash},方法名可以是:find和:create,:find的参数hash包含:conditions, :joins, :include, :offset,:limit, and :readonly options. :create后的参数hash是属性列表。
class Article < ActiveRecord::Base def self.create_with_scope with_scope(:find => { :conditions => "blog_id = 1" }, :create => { :blog_id => 1 }) do find(1) # => SELECT * from articles WHERE blog_id = 1 AND id = 1 a = create(1) a.blog_id # => 1 end end end
嵌套时:conditions, :include,:joins 会被merge
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_exclusive_scope 忽略之前的所以范围定义
class Article < ActiveRecord::Base def self.find_with_exclusive_scope with_scope(:find => { :conditions => "blog_id = 1", :limit => 1 }) do with_exclusive_scope(:find => { :limit => 10 }) find(:all) # => SELECT * from articles LIMIT 10 end end end end
Note: the +:find+ scope also has effect on update and deletion methods, like update_all and delete_all.
[ hide source ]
# File vendor/rails/activerecord/lib/active_record/base.rb, line 2089 2089: def with_scope(method_scoping = {}, action = :merge, &block) 2090: method_scoping = method_scoping.method_scoping if method_scoping.respond_to?(:method_scoping) 2091: 2092: # Dup first and second level of hash (method and params). 2093: method_scoping = method_scoping.inject({}) do |hash, (method, params)| 2094: hash[method] = (params == true) ? params : params.dup 2095: hash 2096: end 2097: 2098: method_scoping.assert_valid_keys([ :find, :create ]) 2099: 2100: if f = method_scoping[:find] 2101: f.assert_valid_keys(VALID_FIND_OPTIONS) 2102: set_readonly_option! f 2103: end 2104: 2105: # Merge scopings 2106: if [:merge, :reverse_merge].include?(action) && current_scoped_methods 2107: method_scoping = current_scoped_methods.inject(method_scoping) do |hash, (method, params)| 2108: case hash[method] 2109: when Hash 2110: if method == :find 2111: (hash[method].keys + params.keys).uniq.each do |key| 2112: merge = hash[method][key] && params[key] # merge if both scopes have the same key 2113: if key == :conditions && merge 2114: if params[key].is_a?(Hash) && hash[method][key].is_a?(Hash) 2115: hash[method][key] = merge_conditions(hash[method][key].deep_merge(params[key])) 2116: else 2117: hash[method][key] = merge_conditions(params[key], hash[method][key]) 2118: end 2119: elsif key == :include && merge 2120: hash[method][key] = merge_includes(hash[method][key], params[key]).uniq 2121: elsif key == :joins && merge 2122: hash[method][key] = merge_joins(params[key], hash[method][key]) 2123: else 2124: hash[method][key] = hash[method][key] || params[key] 2125: end 2126: end 2127: else 2128: if action == :reverse_merge 2129: hash[method] = hash[method].merge(params) 2130: else 2131: hash[method] = params.merge(hash[method]) 2132: end 2133: end 2134: else 2135: hash[method] = params 2136: end 2137: hash 2138: end 2139: end 2140: 2141: self.scoped_methods << method_scoping 2142: begin 2143: yield 2144: ensure 2145: self.scoped_methods.pop 2146: end 2147: end
莫愁前路无知己,天下无人不识君。