Permalink
Browse files

Backport of lazy evaluation of has_many ..., :dependent => :___

[#2627 state:committed]

Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
  • Loading branch information...
1 parent a72bcdb commit e617af13a2cee3278c6f76121bbb777fc7f0fea5 @pixeltrix pixeltrix committed with jeremy Apr 4, 2010
View
40 activerecord/lib/active_record/associations.rb
@@ -1415,14 +1415,6 @@ def find_with_associations(options = {})
# finder conditions.
def configure_dependency_for_has_many(reflection, extra_conditions = nil)
if reflection.options.include?(:dependent)
- # Add polymorphic type if the :as option is present
- dependent_conditions = []
- dependent_conditions << "#{reflection.primary_key_name} = \#{record.#{reflection.name}.send(:owner_quoted_id)}"
- dependent_conditions << "#{reflection.options[:as]}_type = '#{base_class.name}'" if reflection.options[:as]
- dependent_conditions << sanitize_sql(reflection.options[:conditions], reflection.quoted_table_name) if reflection.options[:conditions]
- dependent_conditions << extra_conditions if extra_conditions
- dependent_conditions = dependent_conditions.collect {|where| "(#{where})" }.join(" AND ")
- dependent_conditions = dependent_conditions.gsub('@', '\@')
case reflection.options[:dependent]
when :destroy
method_name = "has_many_dependent_destroy_for_#{reflection.name}".to_sym
@@ -1431,24 +1423,22 @@ def configure_dependency_for_has_many(reflection, extra_conditions = nil)
end
before_destroy method_name
when :delete_all
- module_eval %Q{
- before_destroy do |record| # before_destroy do |record|
- delete_all_has_many_dependencies(record, # delete_all_has_many_dependencies(record,
- "#{reflection.name}", # "posts",
- #{reflection.class_name}, # Post,
- %@#{dependent_conditions}@) # %@...@) # this is a string literal like %(...)
- end # end
- }
+ before_destroy do |record|
+ record.class.send(:delete_all_has_many_dependencies,
+ record,
+ reflection.name,
+ reflection.klass,
+ reflection.dependent_conditions(record, record.class, extra_conditions))
+ end
when :nullify
- module_eval %Q{
- before_destroy do |record| # before_destroy do |record|
- nullify_has_many_dependencies(record, # nullify_has_many_dependencies(record,
- "#{reflection.name}", # "posts",
- #{reflection.class_name}, # Post,
- "#{reflection.primary_key_name}", # "user_id",
- %@#{dependent_conditions}@) # %@...@) # this is a string literal like %(...)
- end # end
- }
+ before_destroy do |record|
+ record.class.send(:nullify_has_many_dependencies,
+ record,
+ reflection.name,
+ reflection.klass,
+ reflection.primary_key_name,
+ reflection.dependent_conditions(record, record.class, extra_conditions))
+ end
else
raise ArgumentError, "The :dependent option expects either :destroy, :delete_all, or :nullify (#{reflection.options[:dependent].inspect})"
end
View
11 activerecord/lib/active_record/reflection.rb
@@ -277,6 +277,17 @@ def validate?
!options[:validate].nil? ? options[:validate] : (options[:autosave] == true || macro == :has_many)
end
+ def dependent_conditions(record, base_class, extra_conditions)
+ dependent_conditions = []
+ dependent_conditions << "#{primary_key_name} = #{record.send(name).send(:owner_quoted_id)}"
+ dependent_conditions << "#{options[:as]}_type = '#{base_class.name}'" if options[:as]
+ dependent_conditions << klass.send(:sanitize_sql, options[:conditions]) if options[:conditions]
+ dependent_conditions = dependent_conditions.collect {|where| "(#{where})" }.join(" AND ")
+ dependent_conditions << extra_conditions if extra_conditions
+ dependent_conditions = dependent_conditions.gsub('@', '\@')
+ dependent_conditions
+ end
+
private
def derive_class_name
class_name = name.to_s.camelize
View
18 activerecord/test/cases/associations/has_many_associations_test.rb
@@ -1138,5 +1138,23 @@ def test_normal_method_call_in_association_proxy
def test_instance_eval_in_association_proxy
assert_equal 'Welcome to the weblog', Comment.all.map { |comment| comment.post }.sort_by(&:id).first.instance_eval{title}
end
+
+ def test_defining_has_many_association_with_delete_all_dependency_lazily_evaluates_target_class
+ ActiveRecord::Reflection::AssociationReflection.any_instance.expects(:class_name).never
+ class_eval <<-EOF
+ class DeleteAllModel < ActiveRecord::Base
+ has_many :nonentities, :dependent => :delete_all
+ end
+ EOF
+ end
+
+ def test_defining_has_many_association_with_nullify_dependency_lazily_evaluates_target_class
+ ActiveRecord::Reflection::AssociationReflection.any_instance.expects(:class_name).never
+ class_eval <<-EOF
+ class NullifyModel < ActiveRecord::Base
+ has_many :nonentities, :dependent => :nullify
+ end
+ EOF
+ end
end

0 comments on commit e617af1

Please sign in to comment.