| 950 | | # Scope parameters to method calls within the block. Takes a hash of method_name => parameters hash. |
|---|
| 951 | | # method_name may be :find or :create. :find parameters may include the <tt>:conditions</tt>, <tt>:joins</tt>, |
|---|
| 952 | | # <tt>:include</tt>, <tt>:offset</tt>, <tt>:limit</tt>, and <tt>:readonly</tt> options. :create parameters are an attributes hash. |
|---|
| 953 | | # |
|---|
| 954 | | # Article.with_scope(:find => { :conditions => "blog_id = 1" }, :create => { :blog_id => 1 }) do |
|---|
| 955 | | # Article.find(1) # => SELECT * from articles WHERE blog_id = 1 AND id = 1 |
|---|
| 956 | | # a = Article.create(1) |
|---|
| 957 | | # a.blog_id # => 1 |
|---|
| 958 | | # end |
|---|
| 959 | | # |
|---|
| 960 | | # In nested scopings, all previous parameters are overwritten by inner rule |
|---|
| 961 | | # except :conditions in :find, that are merged as hash. |
|---|
| 962 | | # |
|---|
| 963 | | # Article.with_scope(:find => { :conditions => "blog_id = 1", :limit => 1 }, :create => { :blog_id => 1 }) do |
|---|
| 964 | | # Article.with_scope(:find => { :limit => 10}) |
|---|
| 965 | | # Article.find(:all) # => SELECT * from articles WHERE blog_id = 1 LIMIT 10 |
|---|
| 966 | | # end |
|---|
| 967 | | # Article.with_scope(:find => { :conditions => "author_id = 3" }) |
|---|
| 968 | | # Article.find(:all) # => SELECT * from articles WHERE blog_id = 1 AND author_id = 3 LIMIT 1 |
|---|
| 969 | | # end |
|---|
| 970 | | # end |
|---|
| 971 | | # |
|---|
| 972 | | # You can ignore any previous scopings by using <tt>with_exclusive_scope</tt> method. |
|---|
| 973 | | # |
|---|
| 974 | | # Article.with_scope(:find => { :conditions => "blog_id = 1", :limit => 1 }) do |
|---|
| 975 | | # Article.with_exclusive_scope(:find => { :limit => 10 }) |
|---|
| 976 | | # Article.find(:all) # => SELECT * from articles LIMIT 10 |
|---|
| 977 | | # end |
|---|
| 978 | | # end |
|---|
| 979 | | def with_scope(method_scoping = {}, action = :merge, &block) |
|---|
| 980 | | method_scoping = method_scoping.method_scoping if method_scoping.respond_to?(:method_scoping) |
|---|
| 981 | | |
|---|
| 982 | | # Dup first and second level of hash (method and params). |
|---|
| 983 | | method_scoping = method_scoping.inject({}) do |hash, (method, params)| |
|---|
| 984 | | hash[method] = (params == true) ? params : params.dup |
|---|
| 985 | | hash |
|---|
| 986 | | end |
|---|
| 987 | | |
|---|
| 988 | | method_scoping.assert_valid_keys([ :find, :create ]) |
|---|
| 989 | | |
|---|
| 990 | | if f = method_scoping[:find] |
|---|
| 991 | | f.assert_valid_keys([ :conditions, :joins, :select, :include, :from, :offset, :limit, :order, :readonly, :lock ]) |
|---|
| 992 | | set_readonly_option! f |
|---|
| 993 | | end |
|---|
| 994 | | |
|---|
| 995 | | # Merge scopings |
|---|
| 996 | | if action == :merge && current_scoped_methods |
|---|
| 997 | | method_scoping = current_scoped_methods.inject(method_scoping) do |hash, (method, params)| |
|---|
| 998 | | case hash[method] |
|---|
| 999 | | when Hash |
|---|
| 1000 | | if method == :find |
|---|
| 1001 | | (hash[method].keys + params.keys).uniq.each do |key| |
|---|
| 1002 | | merge = hash[method][key] && params[key] # merge if both scopes have the same key |
|---|
| 1003 | | if key == :conditions && merge |
|---|
| 1004 | | hash[method][key] = [params[key], hash[method][key]].collect{ |sql| "( %s )" % sanitize_sql(sql) }.join(" AND ") |
|---|
| 1005 | | elsif key == :include && merge |
|---|
| 1006 | | hash[method][key] = merge_includes(hash[method][key], params[key]).uniq |
|---|
| 1007 | | else |
|---|
| 1008 | | hash[method][key] = hash[method][key] || params[key] |
|---|
| 1009 | | end |
|---|
| 1010 | | end |
|---|
| 1011 | | else |
|---|
| 1012 | | hash[method] = params.merge(hash[method]) |
|---|
| 1013 | | end |
|---|
| 1014 | | else |
|---|
| 1015 | | hash[method] = params |
|---|
| 1016 | | end |
|---|
| 1017 | | hash |
|---|
| 1018 | | end |
|---|
| 1019 | | end |
|---|
| 1020 | | |
|---|
| 1021 | | self.scoped_methods << method_scoping |
|---|
| 1022 | | |
|---|
| 1023 | | begin |
|---|
| 1024 | | yield |
|---|
| 1025 | | ensure |
|---|
| 1026 | | self.scoped_methods.pop |
|---|
| 1027 | | end |
|---|
| 1028 | | end |
|---|
| 1029 | | |
|---|
| 1030 | | # Works like with_scope, but discards any nested properties. |
|---|
| 1031 | | def with_exclusive_scope(method_scoping = {}, &block) |
|---|
| 1032 | | with_scope(method_scoping, :overwrite, &block) |
|---|
| 1033 | | end |
|---|
| 1034 | | |
|---|
| | 1327 | # Scope parameters to method calls within the block. Takes a hash of method_name => parameters hash. |
|---|
| | 1328 | # method_name may be :find or :create. :find parameters may include the <tt>:conditions</tt>, <tt>:joins</tt>, |
|---|
| | 1329 | # <tt>:include</tt>, <tt>:offset</tt>, <tt>:limit</tt>, and <tt>:readonly</tt> options. :create parameters are an attributes hash. |
|---|
| | 1330 | # |
|---|
| | 1331 | # class Article < ActiveRecord::Base |
|---|
| | 1332 | # def self.create_with_scope |
|---|
| | 1333 | # with_scope(:find => { :conditions => "blog_id = 1" }, :create => { :blog_id => 1 }) do |
|---|
| | 1334 | # find(1) # => SELECT * from articles WHERE blog_id = 1 AND id = 1 |
|---|
| | 1335 | # a = create(1) |
|---|
| | 1336 | # a.blog_id # => 1 |
|---|
| | 1337 | # end |
|---|
| | 1338 | # end |
|---|
| | 1339 | # end |
|---|
| | 1340 | # |
|---|
| | 1341 | # In nested scopings, all previous parameters are overwritten by inner rule |
|---|
| | 1342 | # except :conditions in :find, that are merged as hash. |
|---|
| | 1343 | # |
|---|
| | 1344 | # class Article < ActiveRecord::Base |
|---|
| | 1345 | # def self.find_with_scope |
|---|
| | 1346 | # with_scope(:find => { :conditions => "blog_id = 1", :limit => 1 }, :create => { :blog_id => 1 }) do |
|---|
| | 1347 | # with_scope(:find => { :limit => 10}) |
|---|
| | 1348 | # find(:all) # => SELECT * from articles WHERE blog_id = 1 LIMIT 10 |
|---|
| | 1349 | # end |
|---|
| | 1350 | # with_scope(:find => { :conditions => "author_id = 3" }) |
|---|
| | 1351 | # find(:all) # => SELECT * from articles WHERE blog_id = 1 AND author_id = 3 LIMIT 1 |
|---|
| | 1352 | # end |
|---|
| | 1353 | # end |
|---|
| | 1354 | # end |
|---|
| | 1355 | # end |
|---|
| | 1356 | # |
|---|
| | 1357 | # You can ignore any previous scopings by using <tt>with_exclusive_scope</tt> method. |
|---|
| | 1358 | # |
|---|
| | 1359 | # class Article < ActiveRecord::Base |
|---|
| | 1360 | # def self.find_with_exclusive_scope |
|---|
| | 1361 | # with_scope(:find => { :conditions => "blog_id = 1", :limit => 1 }) do |
|---|
| | 1362 | # with_exclusive_scope(:find => { :limit => 10 }) |
|---|
| | 1363 | # find(:all) # => SELECT * from articles LIMIT 10 |
|---|
| | 1364 | # end |
|---|
| | 1365 | # end |
|---|
| | 1366 | # end |
|---|
| | 1367 | # end |
|---|
| | 1368 | def with_scope(method_scoping = {}, action = :merge, &block) |
|---|
| | 1369 | method_scoping = method_scoping.method_scoping if method_scoping.respond_to?(:method_scoping) |
|---|
| | 1370 | |
|---|
| | 1371 | # Dup first and second level of hash (method and params). |
|---|
| | 1372 | method_scoping = method_scoping.inject({}) do |hash, (method, params)| |
|---|
| | 1373 | hash[method] = (params == true) ? params : params.dup |
|---|
| | 1374 | hash |
|---|
| | 1375 | end |
|---|
| | 1376 | |
|---|
| | 1377 | method_scoping.assert_valid_keys([ :find, :create ]) |
|---|
| | 1378 | |
|---|
| | 1379 | if f = method_scoping[:find] |
|---|
| | 1380 | f.assert_valid_keys([ :conditions, :joins, :select, :include, :from, :offset, :limit, :order, :readonly, :lock ]) |
|---|
| | 1381 | set_readonly_option! f |
|---|
| | 1382 | end |
|---|
| | 1383 | |
|---|
| | 1384 | # Merge scopings |
|---|
| | 1385 | if action == :merge && current_scoped_methods |
|---|
| | 1386 | method_scoping = current_scoped_methods.inject(method_scoping) do |hash, (method, params)| |
|---|
| | 1387 | case hash[method] |
|---|
| | 1388 | when Hash |
|---|
| | 1389 | if method == :find |
|---|
| | 1390 | (hash[method].keys + params.keys).uniq.each do |key| |
|---|
| | 1391 | merge = hash[method][key] && params[key] # merge if both scopes have the same key |
|---|
| | 1392 | if key == :conditions && merge |
|---|
| | 1393 | hash[method][key] = [params[key], hash[method][key]].collect{ |sql| "( %s )" % sanitize_sql(sql) }.join(" AND ") |
|---|
| | 1394 | elsif key == :include && merge |
|---|
| | 1395 | hash[method][key] = merge_includes(hash[method][key], params[key]).uniq |
|---|
| | 1396 | else |
|---|
| | 1397 | hash[method][key] = hash[method][key] || params[key] |
|---|
| | 1398 | end |
|---|
| | 1399 | end |
|---|
| | 1400 | else |
|---|
| | 1401 | hash[method] = params.merge(hash[method]) |
|---|
| | 1402 | end |
|---|
| | 1403 | else |
|---|
| | 1404 | hash[method] = params |
|---|
| | 1405 | end |
|---|
| | 1406 | hash |
|---|
| | 1407 | end |
|---|
| | 1408 | end |
|---|
| | 1409 | |
|---|
| | 1410 | self.scoped_methods << method_scoping |
|---|
| | 1411 | |
|---|
| | 1412 | begin |
|---|
| | 1413 | yield |
|---|
| | 1414 | ensure |
|---|
| | 1415 | self.scoped_methods.pop |
|---|
| | 1416 | end |
|---|
| | 1417 | end |
|---|
| | 1418 | |
|---|
| | 1419 | # Works like with_scope, but discards any nested properties. |
|---|
| | 1420 | def with_exclusive_scope(method_scoping = {}, &block) |
|---|
| | 1421 | with_scope(method_scoping, :overwrite, &block) |
|---|
| | 1422 | end |
|---|
| | 1423 | |
|---|