Skip to content

Commit

Permalink
Added that Base#find takes an optional options hash, including :condi…
Browse files Browse the repository at this point in the history
…tions. Base#find_on_conditions deprecated in favor of #find with :conditions #407 [bitsweat]

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@305 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information
dhh committed Jan 1, 2005
1 parent 86df396 commit 6bd672e
Show file tree
Hide file tree
Showing 8 changed files with 246 additions and 134 deletions.
2 changes: 2 additions & 0 deletions activerecord/CHANGELOG
@@ -1,5 +1,7 @@
*SVN* *SVN*


* Added that Base#find takes an optional options hash, including :conditions. Base#find_on_conditions deprecated in favor of #find with :conditions #407 [bitsweat]

* Added a db2 adapter that only depends on the Ruby/DB2 bindings (http://raa.ruby-lang.org/project/ruby-db2/) #386 [Maik Schmidt] * Added a db2 adapter that only depends on the Ruby/DB2 bindings (http://raa.ruby-lang.org/project/ruby-db2/) #386 [Maik Schmidt]


* Added the final touches to the Microsoft SQL Server adapter by DeLynn Berry that makes it suitable for actual use #394 [DeLynn Barry] * Added the final touches to the Microsoft SQL Server adapter by DeLynn Berry that makes it suitable for actual use #394 [DeLynn Barry]
Expand Down
Expand Up @@ -100,39 +100,36 @@ def interpolate_sql_options!(options, *keys)
def interpolate_sql(sql, record = nil) def interpolate_sql(sql, record = nil)
@owner.send(:interpolate_sql, sql, record) @owner.send(:interpolate_sql, sql, record)
end end


def sanitize_sql(sql)
@association_class.send(:sanitize_sql, sql)
end

def extract_options_from_args!(args)
@owner.send(:extract_options_from_args!, args)
end

private private
def load_collection def load_collection
begin if loaded?
@collection = find_all_records unless loaded? @collection
rescue ActiveRecord::RecordNotFound else
@collection = [] begin
@collection = find_all_records
rescue ActiveRecord::RecordNotFound
@collection = []
end
end end
end end


def raise_on_type_mismatch(record) def raise_on_type_mismatch(record)
raise ActiveRecord::AssociationTypeMismatch, "#{@association_class} expected, got #{record.class}" unless record.is_a?(@association_class) raise ActiveRecord::AssociationTypeMismatch, "#{@association_class} expected, got #{record.class}" unless record.is_a?(@association_class)
end end



def load_collection_to_array
return unless @collection_array.nil?
begin
@collection_array = find_all_records
rescue ActiveRecord::StatementInvalid, ActiveRecord::RecordNotFound
@collection_array = []
end
end

def duplicated_records_array(records)
records = [records] unless records.is_a?(Array) || records.is_a?(ActiveRecord::Associations::AssociationCollection)
records.dup
end

# Array#flatten has problems with rescursive arrays. Going one level deeper solves the majority of the problems. # Array#flatten has problems with rescursive arrays. Going one level deeper solves the majority of the problems.
def flatten_deeper(array) def flatten_deeper(array)
array.collect { |element| element.respond_to?(:flatten) ? element.flatten : element }.flatten array.collect { |element| element.respond_to?(:flatten) ? element.flatten : element }.flatten
end end
end end
end end
end end
Expand Up @@ -38,15 +38,42 @@ def clear
self self
end end


def find(association_id = nil, &block) def find_first
if block_given? || @options[:finder_sql] load_collection.first
load_collection end
@collection.find(&block)
def find(*args)
# Return an Array if multiple ids are given.
expects_array = args.first.kind_of?(Array)

ids = args.flatten.compact.uniq

# If no block is given, raise RecordNotFound.
if ids.empty?
raise RecordNotFound, "Couldn't find #{@association_class.name} without an ID#{conditions}"

# If using a custom finder_sql, scan the entire collection.
elsif @options[:finder_sql]
if ids.size == 1
id = ids.first
record = load_collection.detect { |record| id == record.id }
expects_array? ? [record] : record
else
load_collection.select { |record| ids.include?(record.id) }
end

# Otherwise, construct a query.
else else
if loaded? ids_list = ids.map { |id| @owner.send(:quote, id) }.join(',')
find_all { |record| record.id == association_id.to_i }.first records = find_all_records(@finder_sql.sub(/ORDER BY/, "AND j.#{@association_foreign_key} IN (#{ids_list}) ORDER BY"))
if records.size == ids.size
if ids.size == 1 and !expects_array
records.first
else
records
end
else else
find_all_records(@finder_sql.sub(/ORDER BY/, "AND j.#{@association_foreign_key} = #{@owner.send(:quote, association_id)} ORDER BY")).first raise RecordNotFound, "Couldn't find #{@association_class.name} with ID in (#{ids_list})"
end end
end end
end end
Expand All @@ -70,10 +97,9 @@ def find_all_records(sql = @finder_sql)
records = @association_class.find_by_sql(sql) records = @association_class.find_by_sql(sql)
@options[:uniq] ? uniq(records) : records @options[:uniq] ? uniq(records) : records
end end

def count_records def count_records
load_collection load_collection.size
@collection.size
end end


def insert_record(record) def insert_record(record)
Expand Down
64 changes: 39 additions & 25 deletions activerecord/lib/active_record/associations/has_many_association.rb
Expand Up @@ -3,12 +3,13 @@ module Associations
class HasManyAssociation < AssociationCollection #:nodoc: class HasManyAssociation < AssociationCollection #:nodoc:
def initialize(owner, association_name, association_class_name, association_class_primary_key_name, options) def initialize(owner, association_name, association_class_name, association_class_primary_key_name, options)
super(owner, association_name, association_class_name, association_class_primary_key_name, options) super(owner, association_name, association_class_name, association_class_primary_key_name, options)
@conditions = @association_class.send(:sanitize_conditions, options[:conditions]) @conditions = sanitize_sql(options[:conditions])


if options[:finder_sql] if options[:finder_sql]
@finder_sql = interpolate_sql(options[:finder_sql]) @finder_sql = interpolate_sql(options[:finder_sql])
else else
@finder_sql = "#{@association_class_primary_key_name} = #{@owner.quoted_id} #{@conditions ? " AND " + interpolate_sql(@conditions) : ""}" @finder_sql = "#{@association_class_primary_key_name} = #{@owner.quoted_id}"
@finder_sql << " AND #{@conditions}" if @conditions
end end


if options[:counter_sql] if options[:counter_sql]
Expand All @@ -35,29 +36,46 @@ def build(attributes = {})
record record
end end


def find_all(runtime_conditions = nil, orderings = nil, limit = nil, joins = nil, &block) def find_all(runtime_conditions = nil, orderings = nil, limit = nil, joins = nil)
if block_given? || @options[:finder_sql] if @options[:finder_sql]
load_collection records = @association_class.find_by_sql(@finder_sql)
@collection.find_all(&block)
else else
@association_class.find_all( sql = @finder_sql
"#{@association_class_primary_key_name} = #{@owner.quoted_id}" + sql << " AND #{sanitize_sql(runtime_conditions)}" if runtime_conditions
"#{@conditions ? " AND " + @conditions : ""}#{runtime_conditions ? " AND " + @association_class.send(:sanitize_conditions, runtime_conditions) : ""}", orderings ||= @options[:order]
orderings, records = @association_class.find_all(sql, orderings, limit, joins)
limit,
joins
)
end end
end end


def find(association_id = nil, &block) # Find the first associated record. All arguments are optional.
if block_given? || @options[:finder_sql] def find_first(conditions = nil, orderings = nil)
load_collection find_all(conditions, orderings, 1).first
@collection.find(&block) end

def find(*args)
# Return an Array if multiple ids are given.
expects_array = args.first.kind_of?(Array)

ids = args.flatten.compact.uniq

# If no ids given, raise RecordNotFound.
if ids.empty?
raise RecordNotFound, "Couldn't find #{@association_class.name} without an ID"

# If using a custom finder_sql, scan the entire collection.
elsif @options[:finder_sql]
if ids.size == 1
id = ids.first
record = load_collection.detect { |record| id == record.id }
expects_array? ? [record] : record
else
load_collection.select { |record| ids.include?(record.id) }
end

# Otherwise, delegate to association class with conditions.
else else
@association_class.find_on_conditions(association_id, args << { :conditions => "#{@association_class_primary_key_name} = '#{@owner.id}' #{@conditions ? " AND " + @conditions : ""}" }
"#{@association_class_primary_key_name} = #{@owner.quoted_id}#{@conditions ? " AND " + @conditions : ""}" @association_class.find(*args)
)
end end
end end


Expand All @@ -71,11 +89,7 @@ def clear


protected protected
def find_all_records def find_all_records
if @options[:finder_sql] find_all
@association_class.find_by_sql(@finder_sql)
else
@association_class.find_all(@finder_sql, @options[:order] ? @options[:order] : nil)
end
end end


def count_records def count_records
Expand Down

0 comments on commit 6bd672e

Please sign in to comment.