提交 2fbe0ae7 编写于 作者: J Jeremy Kemper

Support nil and Array in :conditions => { attr => value } hashes. Closes #6548.

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@5435 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
上级 5b979ed8
*SVN*
* Support nil and Array in :conditions => { attr => value } hashes. #6548 [Assaf, Jeremy Kemper]
find(:all, :conditions => { :topic_id => [1, 2, 3], :last_read => nil }
* Consistently use LOWER() for uniqueness validations (rather than mixing with UPPER()) so the database can always use a functional index on the lowercased column. #6495 [Si]
* SQLite: fix calculations workaround, remove count(distinct) query rewrite, cleanup test connection scripts. [Jeremy Kemper]
......
......@@ -986,7 +986,7 @@ def find_initial(options)
options.update(:limit => 1) unless options[:include]
find_every(options).first
end
def find_every(options)
records = scoped?(:find, :include) || options[:include] ?
find_with_associations(options) :
......@@ -996,11 +996,11 @@ def find_every(options)
records
end
def find_from_ids(ids, options)
expects_array = ids.first.kind_of?(Array)
expects_array = ids.first.kind_of?(Array)
return ids.first if expects_array && ids.first.empty?
ids = ids.flatten.compact.uniq
case ids.size
......@@ -1192,16 +1192,16 @@ def method_missing(method_id, *arguments)
attribute_names = extract_attribute_names_from_match(match)
super unless all_attributes_exists?(attribute_names)
conditions = construct_conditions_from_arguments(attribute_names, arguments)
attributes = construct_attributes_from_arguments(attribute_names, arguments)
case extra_options = arguments[attribute_names.size]
when nil
options = { :conditions => conditions }
options = { :conditions => attributes }
set_readonly_option!(options)
ActiveSupport::Deprecation.silence { send(finder, options) }
when Hash
finder_options = extra_options.merge(:conditions => conditions)
finder_options = extra_options.merge(:conditions => attributes)
validate_find_options(finder_options)
set_readonly_option!(finder_options)
......@@ -1215,7 +1215,7 @@ def method_missing(method_id, *arguments)
else
ActiveSupport::Deprecation.silence do
send(deprecated_finder, conditions, *arguments[attribute_names.length..-1])
send(deprecated_finder, sanitize_sql(attributes), *arguments[attribute_names.length..-1])
end
end
elsif match = /find_or_(initialize|create)_by_([_a-zA-Z]\w*)/.match(method_id.to_s)
......@@ -1223,9 +1223,11 @@ def method_missing(method_id, *arguments)
attribute_names = extract_attribute_names_from_match(match)
super unless all_attributes_exists?(attribute_names)
options = { :conditions => construct_conditions_from_arguments(attribute_names, arguments) }
attributes = construct_attributes_from_arguments(attribute_names, arguments)
options = { :conditions => attributes }
set_readonly_option!(options)
find_initial(options) || send(instantiator, construct_attributes_from_arguments(attribute_names, arguments))
find_initial(options) || send(instantiator, attributes)
else
super
end
......@@ -1247,12 +1249,6 @@ def extract_attribute_names_from_match(match)
match.captures.last.split('_and_')
end
def construct_conditions_from_arguments(attribute_names, arguments)
conditions = []
attribute_names.each_with_index { |name, idx| conditions << "#{table_name}.#{connection.quote_column_name(name)} #{attribute_condition(arguments[idx])} " }
[ conditions.join(" AND "), *arguments[0...attribute_names.length] ]
end
def construct_attributes_from_arguments(attribute_names, arguments)
attributes = {}
attribute_names.each_with_index { |name, idx| attributes[name] = arguments[idx] }
......@@ -1275,7 +1271,7 @@ def attribute_condition(argument)
def expand_id_conditions(id_or_conditions)
case id_or_conditions
when Array, Hash then id_or_conditions
else construct_conditions_from_arguments([primary_key], [id_or_conditions])
else sanitize_sql(primary_key => id_or_conditions)
end
end
......@@ -1377,26 +1373,32 @@ def class_name_of_active_record_descendant(klass) #:nodoc:
klass.base_class.name
end
#Accepts an array, hash, or string of sql conditions and
#deals with them accordingly
# Accepts an array, hash, or string of sql conditions and sanitizes
# them into a valid SQL fragment.
# ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'"
# { :name => "foo'bar", :group_id => 4 } returns "name='foo''bar' and group_id='4'"
# "name='foo''bar' and group_id='4'" returns "name='foo''bar' and group_id='4'"
def sanitize_sql(condition)
return sanitize_sql_array(condition) if condition.is_a?(Array)
return sanitize_sql_hash(condition) if condition.is_a?(Hash)
condition
case condition
when Array; sanitize_sql_array(condition)
when Hash; sanitize_sql_hash(condition)
else condition
end
end
# Accepts a hash of conditions. The hash has each key/value or attribute/value pair
# sanitized and interpolated into the sql statement.
# { :name => "foo'bar", :group_id => 4 } returns "name='foo''bar' and group_id= 4"
def sanitize_sql_hash(hash)
hash.collect { |attrib, value|
"#{table_name}.#{connection.quote_column_name(attrib)} = #{quote_value(value)}"
}.join(" AND ")
# Sanitizes a hash of attribute/value pairs into SQL conditions.
# { :name => "foo'bar", :group_id => 4 }
# # => "name='foo''bar' and group_id= 4"
# { :status => nil, :group_id => [1,2,3] }
# # => "status IS NULL and group_id IN (1,2,3)"
def sanitize_sql_hash(attrs)
conditions = attrs.map do |attr, value|
"#{table_name}.#{connection.quote_column_name(attr)} #{attribute_condition(value)}"
end.join(' AND ')
replace_bind_variables(conditions, attrs.values)
end
# Accepts an array of conditions. The array has each value
# sanitized and interpolated into the sql statement.
# ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'"
......
......@@ -161,10 +161,22 @@ def test_hash_condition_find_malformed
Company.find(:first, :conditions => { :id => 2, :dhh => true })
}
end
def test_hash_condition_find_with_escaped_characters
Company.create("name" => "Ain't noth'n like' \#stuff")
assert Company.find(:first, :conditions => { :name => "Ain't noth'n like' \#stuff"})
assert Company.find(:first, :conditions => { :name => "Ain't noth'n like' \#stuff" })
end
def test_hash_condition_find_with_array
p1, p2 = Post.find(:all, :limit => 2, :order => 'id asc')
assert_equal [p1, p2], Post.find(:all, :conditions => { :id => [p1, p2] }, :order => 'id asc')
assert_equal [p1, p2], Post.find(:all, :conditions => { :id => [p1, p2.id] }, :order => 'id asc')
end
def test_hash_condition_find_with_nil
topic = Topic.find(:first, :conditions => { :last_read => nil } )
assert_not_nil topic
assert_nil topic.last_read
end
def test_bind_variables
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册