Changeset 4425
- Timestamp:
- 06/03/06 22:15:06 (2 years ago)
- Files:
-
- trunk/activerecord/CHANGELOG (modified) (1 diff)
- trunk/activerecord/lib/active_record/base.rb (modified) (4 diffs)
- trunk/activerecord/test/finder_test.rb (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/activerecord/CHANGELOG
r4424 r4425 1 1 *SVN* 2 3 * Added simple hash conditions to find that'll just convert hash to an AND-based condition string #5143 [hcatlin@gmail.com]. Example: 4 5 Person.find(:all, :conditions => { :last_name => "Catlin", :status => 1 }, :limit => 2) 6 7 ...is the same as: 8 9 Person.find(:all, :conditions => [ "last_name = ? and status = ?", "Catlin", 1 ], :limit => 2) 10 11 This makes it easier to pass in the options from a form or otherwise outside. 12 2 13 3 14 * Fixed issues with BLOB limits, charsets, and booleans for Firebird #5194, #5191, #5189 [kennethkunz@gmail.com] trunk/activerecord/lib/active_record/base.rb
r4415 r4425 82 82 # == Conditions 83 83 # 84 # Conditions can either be specified as a string or an arrayrepresenting the WHERE-part of an SQL statement.84 # Conditions can either be specified as a string, array, or hash representing the WHERE-part of an SQL statement. 85 85 # The array form is to be used when the condition input is tainted and requires sanitization. The string form can 86 # be used for statements that don't involve tainted data. Examples: 86 # be used for statements that don't involve tainted data. The hash form works much like the array form, except 87 # only equality is possible. Examples: 87 88 # 88 89 # class User < ActiveRecord::Base … … 94 95 # find(:first, :conditions => [ "user_name = ? AND password = ?", user_name, password ]) 95 96 # end 97 # 98 # def self.authenticate_safely_simply(user_name, password) 99 # find(:first, :conditions => { :user_name => user_name, :password => password }) 100 # end 96 101 # end 97 102 # 98 103 # The <tt>authenticate_unsafely</tt> method inserts the parameters directly into the query and is thus susceptible to SQL-injection 99 # attacks if the <tt>user_name</tt> and +password+ parameters come directly from a HTTP request. The <tt>authenticate_safely</tt> method,100 # on the other hand, will sanitize the <tt>user_name</tt> and +password+ before inserting them in the query, which will ensure that101 # an attacker can't escape the query and fake the login (or worse).104 # attacks if the <tt>user_name</tt> and +password+ parameters come directly from a HTTP request. The <tt>authenticate_safely</tt> and 105 # <tt>authenticate_safely_simply</tt> both will sanitize the <tt>user_name</tt> and +password+ before inserting them in the query, 106 # which will ensure that an attacker can't escape the query and fake the login (or worse). 102 107 # 103 108 # When using multiple parameters in the conditions, it can easily become hard to read exactly what the fourth or fifth … … 109 114 # { :id => 3, :name => "37signals", :division => "First", :accounting_date => '2005-01-01' } 110 115 # ]) 116 # 117 # Similarly, a simple hash without a statement will generate conditions based on equality with the SQL AND 118 # operator. For instance: 119 # 120 # Student.find(:all, :conditions => { :first_name => "Harvey", :status => 1 }) 121 # Student.find(:all, :conditions => params[:student]) 122 # 111 123 # 112 124 # == Overwriting default accessors … … 1274 1286 end 1275 1287 1276 # Accepts an array or string. The string is returned untouched, but the array has each value 1288 #Accepts an array, hash, or string of sql conditions and 1289 #deals with them accordingly 1290 # ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'" 1291 # { :name => "foo'bar", :group_id => 4 } returns "name='foo''bar' and group_id='4'" 1292 # "name='foo''bar' and group_id='4'" returns "name='foo''bar' and group_id='4'" 1293 def sanitize_sql(condition) 1294 return sanitize_sql_array(condition) if condition.is_a?(Array) 1295 return sanitize_sql_hash(condition) if condition.is_a?(Hash) 1296 condition 1297 end 1298 1299 # Accepts a hash of conditions. The hash has each key/value or attribute/value pair 1300 # sanitized and interpolated into the sql statement. 1301 # { :name => "foo'bar", :group_id => 4 } returns "name='foo''bar' and group_id= 4" 1302 def sanitize_sql_hash(hash) 1303 hash.collect { |attrib, value| 1304 "#{table_name}.#{connection.quote_column_name(attrib)} = #{quote(value)}" 1305 }.join(" AND ") 1306 end 1307 1308 # Accepts an array of conditions. The array has each value 1277 1309 # sanitized and interpolated into the sql statement. 1278 1310 # ["name='%s' and group_id='%s'", "foo'bar", 4] returns "name='foo''bar' and group_id='4'" 1279 def sanitize_sql(ary) 1280 return ary unless ary.is_a?(Array) 1281 1311 def sanitize_sql_array(ary) 1282 1312 statement, *values = ary 1283 1313 if values.first.is_a?(Hash) and statement =~ /:\w+/ trunk/activerecord/test/finder_test.rb
r4393 r4425 118 118 end 119 119 120 def test_find_on_ conditions120 def test_find_on_array_conditions 121 121 assert Topic.find(1, :conditions => ["approved = ?", false]) 122 122 assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => ["approved = ?", true]) } 123 123 end 124 124 125 def test_condition_interpolation 125 def test_find_on_hash_conditions 126 assert Topic.find(1, :conditions => { :approved => false }) 127 assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :approved => true }) } 128 end 129 130 def test_find_on_multiple_hash_conditions 131 assert Topic.find(1, :conditions => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => false }) 132 assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => true }) } 133 assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :author_name => "David", :title => "HHC", :replies_count => 1, :approved => false }) } 134 assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { :author_name => "David", :title => "The First Topic", :replies_count => 1, :approved => true }) } 135 end 136 137 def test_condition_array_interpolation 126 138 assert_kind_of Firm, Company.find(:first, :conditions => ["name = '%s'", "37signals"]) 127 139 assert_nil Company.find(:first, :conditions => ["name = '%s'", "37signals!"]) 128 140 assert_nil Company.find(:first, :conditions => ["name = '%s'", "37signals!' OR 1=1"]) 129 141 assert_kind_of Time, Topic.find(:first, :conditions => ["id = %d", 1]).written_on 142 end 143 144 def test_condition_hash_interpolation 145 assert_kind_of Firm, Company.find(:first, :conditions => { :name => "37signals"}) 146 assert_nil Company.find(:first, :conditions => { :name => "37signals!"}) 147 assert_kind_of Time, Topic.find(:first, :conditions => {:id => 1}).written_on 148 end 149 150 def test_hash_condition_find_malformed 151 assert_raises(ActiveRecord::StatementInvalid) { 152 Company.find(:first, :conditions => { :id => 2, :dhh => true }) 153 } 154 end 155 156 def test_hash_condition_find_with_escaped_characters 157 Company.create("name" => "Ain't noth'n like' \#stuff") 158 assert Company.find(:first, :conditions => { :name => "Ain't noth'n like' \#stuff"}) 130 159 end 131 160