Allow conditions on multiple tables to be specified using hash.

Examples:

  User.all :joins => :items, :conditions => { :age => 10, :items => { :color => 'black' } }
  Item.first :conditions => { :items => { :color => 'red' } }

Note : Hash key in :conditions is referring to the actual table name or the alias defined in query.
This commit is contained in:
Pratik Naik
2008-06-28 01:27:25 +01:00
parent 582bff71c4
commit cd994eff9a
3 changed files with 37 additions and 9 deletions

View File

@@ -1,5 +1,10 @@
*Edge*
* Allow conditions on multiple tables to be specified using hash. [Pratik Naik]. Example:
User.all :joins => :items, :conditions => { :age => 10, :items => { :color => 'black' } }
Item.first :conditions => { :items => { :color => 'red' } }
* Always treat integer :limit as byte length. #420 [Tarmo Tänav]
* Partial updates don't update lock_version if nothing changed. #426 [Daniel Morrison]

View File

@@ -1999,24 +1999,28 @@ module ActiveRecord #:nodoc:
# # => "age BETWEEN 13 AND 18"
# { 'other_records.id' => 7 }
# # => "`other_records`.`id` = 7"
# { :other_records => { :id => 7 } }
# # => "`other_records`.`id` = 7"
# And for value objects on a composed_of relationship:
# { :address => Address.new("123 abc st.", "chicago") }
# # => "address_street='123 abc st.' and address_city='chicago'"
def sanitize_sql_hash_for_conditions(attrs)
def sanitize_sql_hash_for_conditions(attrs, table_name = quoted_table_name)
attrs = expand_hash_conditions_for_aggregates(attrs)
conditions = attrs.map do |attr, value|
attr = attr.to_s
unless value.is_a?(Hash)
attr = attr.to_s
# Extract table name from qualified attribute names.
if attr.include?('.')
table_name, attr = attr.split('.', 2)
table_name = connection.quote_table_name(table_name)
# Extract table name from qualified attribute names.
if attr.include?('.')
table_name, attr = attr.split('.', 2)
table_name = connection.quote_table_name(table_name)
end
"#{table_name}.#{connection.quote_column_name(attr)} #{attribute_condition(value)}"
else
table_name = quoted_table_name
sanitize_sql_hash_for_conditions(value, connection.quote_table_name(attr.to_s))
end
"#{table_name}.#{connection.quote_column_name(attr)} #{attribute_condition(value)}"
end.join(' AND ')
replace_bind_variables(conditions, expand_range_bind_variables(attrs.values))
@@ -2070,6 +2074,8 @@ module ActiveRecord #:nodoc:
expanded = []
bind_vars.each do |var|
next if var.is_a?(Hash)
if var.is_a?(Range)
expanded << var.first
expanded << var.last

View File

@@ -200,6 +200,23 @@ class FinderTest < ActiveRecord::TestCase
assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => { 'topics.approved' => true }) }
end
def test_find_on_hash_conditions_with_hashed_table_name
assert Topic.find(1, :conditions => {:topics => { :approved => false }})
assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1, :conditions => {:topics => { :approved => true }}) }
end
def test_find_with_hash_conditions_on_joined_table
firms = Firm.all :joins => :account, :conditions => {:accounts => { :credit_limit => 50 }}
assert_equal 1, firms.size
assert_equal companies(:first_firm), firms.first
end
def test_find_with_hash_conditions_on_joined_table_and_with_range
firms = DependentFirm.all :joins => :account, :conditions => {:name => 'RailsCore', :accounts => { :credit_limit => 55..60 }}
assert_equal 1, firms.size
assert_equal companies(:rails_core), firms.first
end
def test_find_on_hash_conditions_with_explicit_table_name_and_aggregate
david = customers(:david)
assert Customer.find(david.id, :conditions => { 'customers.name' => david.name, :address => david.address })