aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/base.rb
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record/base.rb')
-rwxr-xr-xactiverecord/lib/active_record/base.rb56
1 files changed, 45 insertions, 11 deletions
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 8420fe2ffe..20ccd9a623 100755
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -346,6 +346,7 @@ module ActiveRecord #:nodoc:
else
return args.first if args.first.kind_of?(Array) && args.first.empty?
expects_array = args.first.kind_of?(Array)
+
conditions = " AND #{sanitize_sql(options[:conditions])}" if options[:conditions]
ids = args.flatten.compact.uniq
@@ -703,12 +704,27 @@ module ActiveRecord #:nodoc:
ensure
logger.level = old_logger_level if logger
end
+
+ # Add constrains to all queries to the same model in the given block.
+ # Currently supported constrains are <tt>:conditions</tt> and <tt>:joins</tt>
+ #
+ # Article.constrain(:conditions => "blog_id = 1") do
+ # Article.find(1) # => SELECT * from articles WHERE blog_id = 1 AND id = 1
+ # end
+ def constrain(options = {}, &block)
+ begin
+ self.scope_constrains = options
+ block.call if block_given?
+ ensure
+ self.scope_constrains = nil
+ end
+ end
# Overwrite the default class equality method to provide support for association proxies.
def ===(object)
object.is_a?(self)
- end
-
+ end
+
private
# Finder methods must instantiate through this method to work with the single-table inheritance model
# that makes it possible to create objects of different types from the same table.
@@ -742,9 +758,9 @@ module ActiveRecord #:nodoc:
def construct_finder_sql(options)
sql = "SELECT #{options[:select] || '*'} FROM #{table_name} "
- sql << " #{options[:joins]} " if options[:joins]
+ add_joins!(sql, options)
add_conditions!(sql, options[:conditions])
- sql << "ORDER BY #{options[:order]} " if options[:order]
+ sql << " ORDER BY #{options[:order]} " if options[:order]
add_limit!(sql, options)
sql
end
@@ -752,11 +768,19 @@ module ActiveRecord #:nodoc:
def add_limit!(sql, options)
connection.add_limit_offset!(sql, options)
end
-
+
+ def add_joins!(sql, options)
+ join = scope_constrains[:joins] || options[:joins]
+ sql << " #{join} " if join
+ end
+
# Adds a sanitized version of +conditions+ to the +sql+ string. Note that it's the passed +sql+ string is changed.
- def add_conditions!(sql, conditions)
- sql << "WHERE #{sanitize_sql(conditions)} " unless conditions.nil?
- sql << (conditions.nil? ? "WHERE " : " AND ") + type_condition unless descends_from_active_record?
+ def add_conditions!(sql, conditions)
+ condition_segments = [scope_constrains[:conditions]]
+ condition_segments << sanitize_sql(conditions) unless conditions.nil?
+ condition_segments << type_condition unless descends_from_active_record?
+ condition_segments.compact!
+ sql << "WHERE #{condition_segments.join(" AND ")} " unless condition_segments.empty?
end
def type_condition
@@ -789,7 +813,7 @@ module ActiveRecord #:nodoc:
attributes.each { |attr_name| super unless column_methods_hash.include?(attr_name.to_sym) }
attr_index = -1
- conditions = attributes.collect { |attr_name| attr_index += 1; "#{attr_name} #{attribute_condition(arguments[attr_index])} " }.join(" AND ")
+ conditions = attributes.collect { |attr_name| attr_index += 1; "#{table_name}.#{attr_name} #{attribute_condition(arguments[attr_index])} " }.join(" AND ")
if arguments[attributes.length].is_a?(Hash)
find(finder, { :conditions => [conditions, *arguments[0...attributes.length]] }.update(arguments[attributes.length]))
@@ -840,8 +864,18 @@ module ActiveRecord #:nodoc:
@@subclasses[self] ||= []
@@subclasses[self] + extra = @@subclasses[self].inject([]) {|list, subclass| list + subclass.subclasses }
end
-
- # Returns the class type of the record using the current module as a prefix. So descendents of
+
+ def scope_constrains
+ Thread.current[:constrains] ||= {}
+ Thread.current[:constrains][self] ||= {}
+ end
+
+ def scope_constrains=(value)
+ Thread.current[:constrains] ||= {}
+ Thread.current[:constrains][self] = value
+ end
+
+ # Returns the class type of the record using the current module as a prefix. So descendents of
# MyApp::Business::Account would be appear as MyApp::Business::AccountSubclass.
def compute_type(type_name)
type_name_with_module(type_name).split("::").inject(Object) do |final_type, part|