aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/associations/builder
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record/associations/builder')
-rw-r--r--activerecord/lib/active_record/associations/builder/association.rb91
-rw-r--r--activerecord/lib/active_record/associations/builder/belongs_to.rb78
-rw-r--r--activerecord/lib/active_record/associations/builder/collection_association.rb71
-rw-r--r--activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb24
-rw-r--r--activerecord/lib/active_record/associations/builder/has_many.rb49
-rw-r--r--activerecord/lib/active_record/associations/builder/has_one.rb34
-rw-r--r--activerecord/lib/active_record/associations/builder/singular_association.rb22
7 files changed, 129 insertions, 240 deletions
diff --git a/activerecord/lib/active_record/associations/builder/association.rb b/activerecord/lib/active_record/associations/builder/association.rb
index c3f32b5ed9..1df876bf62 100644
--- a/activerecord/lib/active_record/associations/builder/association.rb
+++ b/activerecord/lib/active_record/associations/builder/association.rb
@@ -39,6 +39,7 @@ module ActiveRecord::Associations::Builder
def build
validate_options
define_accessors
+ configure_dependency if options[:dependent]
@reflection = model.create_reflection(macro, name, scope, options, model)
super # provides an extension point
@reflection
@@ -52,70 +53,54 @@ module ActiveRecord::Associations::Builder
Association.valid_options
end
- private
-
- def validate_options
- options.assert_valid_keys(valid_options)
- end
+ def validate_options
+ options.assert_valid_keys(valid_options)
+ end
- def define_accessors
- define_readers
- define_writers
- end
+ def define_accessors
+ define_readers
+ define_writers
+ end
- def define_readers
- name = self.name
- mixin.redefine_method(name) do |*params|
- association(name).reader(*params)
+ def define_readers
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
+ def #{name}(*args)
+ association(:#{name}).reader(*args)
end
- end
+ CODE
+ end
- def define_writers
- name = self.name
- mixin.redefine_method("#{name}=") do |value|
- association(name).writer(value)
+ def define_writers
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
+ def #{name}=(value)
+ association(:#{name}).writer(value)
end
- end
-
- def check_valid_dependent!(dependent, valid_options)
- unless valid_options.include?(dependent)
- valid_options_message = valid_options.map(&:inspect).to_sentence(
- words_connector: ', ', two_words_connector: ' or ', last_word_connector: ' or ')
+ CODE
+ end
- raise ArgumentError, "The :dependent option expects either " \
- "#{valid_options_message} (#{dependent.inspect})"
- end
+ def configure_dependency
+ unless valid_dependent_options.include? options[:dependent]
+ raise ArgumentError, "The :dependent option must be one of #{valid_dependent_options}, but is :#{options[:dependent]}"
end
- def dependent_restrict_raises?
- ActiveRecord::Base.dependent_restrict_raises == true
+ if options[:dependent] == :restrict
+ ActiveSupport::Deprecation.warn(
+ "The :restrict option is deprecated. Please use :restrict_with_exception instead, which " \
+ "provides the same functionality."
+ )
end
- def dependent_restrict_deprecation_warning
- if dependent_restrict_raises?
- msg = "In the next release, `:dependent => :restrict` will not raise a `DeleteRestrictionError`. "\
- "Instead, it will add an error on the model. To fix this warning, make sure your code " \
- "isn't relying on a `DeleteRestrictionError` and then add " \
- "`config.active_record.dependent_restrict_raises = false` to your application config."
- ActiveSupport::Deprecation.warn msg
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
+ def #{macro}_dependent_for_#{name}
+ association(:#{name}).handle_dependency
end
- end
+ CODE
- def define_restrict_dependency_method
- name = self.name
- mixin.redefine_method(dependency_method_name) do
- has_one_macro = association(name).reflection.macro == :has_one
- if has_one_macro ? !send(name).nil? : send(name).exists?
- if dependent_restrict_raises?
- raise ActiveRecord::DeleteRestrictionError.new(name)
- else
- key = has_one_macro ? "one" : "many"
- errors.add(:base, :"restrict_dependent_destroy.#{key}",
- :record => self.class.human_attribute_name(name).downcase)
- return false
- end
- end
- end
- end
+ model.before_destroy "#{macro}_dependent_for_#{name}"
+ end
+
+ def valid_dependent_options
+ raise NotImplementedError
+ end
end
end
diff --git a/activerecord/lib/active_record/associations/builder/belongs_to.rb b/activerecord/lib/active_record/associations/builder/belongs_to.rb
index f205a456f7..2f2600b7fb 100644
--- a/activerecord/lib/active_record/associations/builder/belongs_to.rb
+++ b/activerecord/lib/active_record/associations/builder/belongs_to.rb
@@ -1,4 +1,3 @@
-
module ActiveRecord::Associations::Builder
class BelongsTo < SingularAssociation #:nodoc:
def macro
@@ -17,72 +16,51 @@ module ActiveRecord::Associations::Builder
reflection = super
add_counter_cache_callbacks(reflection) if options[:counter_cache]
add_touch_callbacks(reflection) if options[:touch]
- configure_dependency
reflection
end
- private
-
- def add_counter_cache_callbacks(reflection)
- cache_column = reflection.counter_cache_column
- name = self.name
+ def add_counter_cache_callbacks(reflection)
+ cache_column = reflection.counter_cache_column
- method_name = "belongs_to_counter_cache_after_create_for_#{name}"
- mixin.redefine_method(method_name) do
- record = send(name)
- record.class.increment_counter(cache_column, record.id) unless record.nil?
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
+ def belongs_to_counter_cache_after_create_for_#{name}
+ record = #{name}
+ record.class.increment_counter(:#{cache_column}, record.id) unless record.nil?
end
- model.after_create(method_name)
- method_name = "belongs_to_counter_cache_before_destroy_for_#{name}"
- mixin.redefine_method(method_name) do
+ def belongs_to_counter_cache_before_destroy_for_#{name}
unless marked_for_destruction?
- record = send(name)
- record.class.decrement_counter(cache_column, record.id) unless record.nil?
+ record = #{name}
+ record.class.decrement_counter(:#{cache_column}, record.id) unless record.nil?
end
end
- model.before_destroy(method_name)
+ CODE
- model.send(:module_eval,
- "#{reflection.class_name}.send(:attr_readonly,\"#{cache_column}\".intern) if defined?(#{reflection.class_name}) && #{reflection.class_name}.respond_to?(:attr_readonly)", __FILE__, __LINE__
- )
- end
+ model.after_create "belongs_to_counter_cache_after_create_for_#{name}"
+ model.before_destroy "belongs_to_counter_cache_before_destroy_for_#{name}"
- def add_touch_callbacks(reflection)
- name = self.name
- method_name = "belongs_to_touch_after_save_or_destroy_for_#{name}"
- touch = options[:touch]
+ klass = reflection.class_name.safe_constantize
+ klass.attr_readonly cache_column if klass && klass.respond_to?(:attr_readonly)
+ end
- mixin.redefine_method(method_name) do
- record = send(name)
+ def add_touch_callbacks(reflection)
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
+ def belongs_to_touch_after_save_or_destroy_for_#{name}
+ record = #{name}
unless record.nil?
- if touch == true
- record.touch
- else
- record.touch(touch)
- end
+ record.touch #{options[:touch].inspect if options[:touch] != true}
end
end
+ CODE
- model.after_save(method_name)
- model.after_touch(method_name)
- model.after_destroy(method_name)
- end
-
- def configure_dependency
- if dependent = options[:dependent]
- check_valid_dependent! dependent, [:destroy, :delete]
+ model.after_save "belongs_to_touch_after_save_or_destroy_for_#{name}"
+ model.after_touch "belongs_to_touch_after_save_or_destroy_for_#{name}"
+ model.after_destroy "belongs_to_touch_after_save_or_destroy_for_#{name}"
+ end
- method_name = "belongs_to_dependent_#{dependent}_for_#{name}"
- model.send(:class_eval, <<-eoruby, __FILE__, __LINE__ + 1)
- def #{method_name}
- association = #{name}
- association.#{dependent} if association
- end
- eoruby
- model.after_destroy method_name
- end
- end
+ def valid_dependent_options
+ [:destroy, :delete]
+ end
end
end
diff --git a/activerecord/lib/active_record/associations/builder/collection_association.rb b/activerecord/lib/active_record/associations/builder/collection_association.rb
index 3fb0a57450..1b382f7285 100644
--- a/activerecord/lib/active_record/associations/builder/collection_association.rb
+++ b/activerecord/lib/active_record/associations/builder/collection_association.rb
@@ -1,4 +1,3 @@
-
module ActiveRecord::Associations::Builder
class CollectionAssociation < Association #:nodoc:
CALLBACKS = [:before_add, :after_add, :before_remove, :after_remove]
@@ -34,53 +33,53 @@ module ActiveRecord::Associations::Builder
end
end
- private
-
- def wrap_block_extension
- if block_extension
- @extension_module = mod = Module.new(&block_extension)
- silence_warnings do
- model.parent.const_set(extension_module_name, mod)
- end
+ def wrap_block_extension
+ if block_extension
+ @extension_module = mod = Module.new(&block_extension)
+ silence_warnings do
+ model.parent.const_set(extension_module_name, mod)
+ end
- prev_scope = @scope
+ prev_scope = @scope
- if prev_scope
- @scope = proc { |owner| instance_exec(owner, &prev_scope).extending(mod) }
- else
- @scope = proc { extending(mod) }
- end
+ if prev_scope
+ @scope = proc { |owner| instance_exec(owner, &prev_scope).extending(mod) }
+ else
+ @scope = proc { extending(mod) }
end
end
+ end
- def extension_module_name
- @extension_module_name ||= "#{model.name.demodulize}#{name.to_s.camelize}AssociationExtension"
- end
+ def extension_module_name
+ @extension_module_name ||= "#{model.name.demodulize}#{name.to_s.camelize}AssociationExtension"
+ end
- def define_callback(callback_name)
- full_callback_name = "#{callback_name}_for_#{name}"
+ def define_callback(callback_name)
+ full_callback_name = "#{callback_name}_for_#{name}"
- # TODO : why do i need method_defined? I think its because of the inheritance chain
- model.class_attribute full_callback_name.to_sym unless model.method_defined?(full_callback_name)
- model.send("#{full_callback_name}=", Array(options[callback_name.to_sym]))
- end
+ # TODO : why do i need method_defined? I think its because of the inheritance chain
+ model.class_attribute full_callback_name.to_sym unless model.method_defined?(full_callback_name)
+ model.send("#{full_callback_name}=", Array(options[callback_name.to_sym]))
+ end
- def define_readers
- super
+ def define_readers
+ super
- name = self.name
- mixin.redefine_method("#{name.to_s.singularize}_ids") do
- association(name).ids_reader
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
+ def #{name.to_s.singularize}_ids
+ association(:#{name}).ids_reader
end
- end
+ CODE
+ end
- def define_writers
- super
+ def define_writers
+ super
- name = self.name
- mixin.redefine_method("#{name.to_s.singularize}_ids=") do |ids|
- association(name).ids_writer(ids)
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
+ def #{name.to_s.singularize}_ids=(ids)
+ association(:#{name}).ids_writer(ids)
end
- end
+ CODE
+ end
end
end
diff --git a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb
index 8df28ad876..bdac02b5bf 100644
--- a/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb
+++ b/activerecord/lib/active_record/associations/builder/has_and_belongs_to_many.rb
@@ -24,18 +24,16 @@ module ActiveRecord::Associations::Builder
end
end
- private
-
- def define_destroy_hook
- name = self.name
- model.send(:include, Module.new {
- class_eval <<-RUBY, __FILE__, __LINE__ + 1
- def destroy_associations
- association(#{name.to_sym.inspect}).delete_all
- super
- end
- RUBY
- })
- end
+ def define_destroy_hook
+ name = self.name
+ model.send(:include, Module.new {
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
+ def destroy_associations
+ association(:#{name}).delete_all
+ super
+ end
+ RUBY
+ })
+ end
end
end
diff --git a/activerecord/lib/active_record/associations/builder/has_many.rb b/activerecord/lib/active_record/associations/builder/has_many.rb
index 9e60dbc30b..ab8225460a 100644
--- a/activerecord/lib/active_record/associations/builder/has_many.rb
+++ b/activerecord/lib/active_record/associations/builder/has_many.rb
@@ -1,4 +1,3 @@
-
module ActiveRecord::Associations::Builder
class HasMany < CollectionAssociation #:nodoc:
def macro
@@ -9,52 +8,8 @@ module ActiveRecord::Associations::Builder
super + [:primary_key, :dependent, :as, :through, :source, :source_type, :inverse_of]
end
- def build
- reflection = super
- configure_dependency
- reflection
+ def valid_dependent_options
+ [:destroy, :delete_all, :nullify, :restrict, :restrict_with_error, :restrict_with_exception]
end
-
- private
-
- def configure_dependency
- if dependent = options[:dependent]
- check_valid_dependent! dependent, [:destroy, :delete_all, :nullify, :restrict]
- dependent_restrict_deprecation_warning if dependent == :restrict
-
- send("define_#{dependent}_dependency_method")
- model.before_destroy dependency_method_name
- end
- end
-
- def define_destroy_dependency_method
- name = self.name
- mixin.redefine_method(dependency_method_name) do
- send(name).each do |o|
- # No point in executing the counter update since we're going to destroy the parent anyway
- o.mark_for_destruction
- end
-
- send(name).delete_all
- end
- end
-
- def define_delete_all_dependency_method
- name = self.name
- mixin.redefine_method(dependency_method_name) do
- association(name).delete_all
- end
- end
-
- def define_nullify_dependency_method
- name = self.name
- mixin.redefine_method(dependency_method_name) do
- send(name).delete_all
- end
- end
-
- def dependency_method_name
- "has_many_dependent_for_#{name}"
- end
end
end
diff --git a/activerecord/lib/active_record/associations/builder/has_one.rb b/activerecord/lib/active_record/associations/builder/has_one.rb
index 9c84f1913a..0da564f402 100644
--- a/activerecord/lib/active_record/associations/builder/has_one.rb
+++ b/activerecord/lib/active_record/associations/builder/has_one.rb
@@ -1,4 +1,3 @@
-
module ActiveRecord::Associations::Builder
class HasOne < SingularAssociation #:nodoc:
def macro
@@ -15,35 +14,12 @@ module ActiveRecord::Associations::Builder
!options[:through]
end
- def build
- reflection = super
- configure_dependency unless options[:through]
- reflection
+ def configure_dependency
+ super unless options[:through]
end
- private
-
- def configure_dependency
- if dependent = options[:dependent]
- check_valid_dependent! dependent, [:destroy, :delete, :nullify, :restrict]
- dependent_restrict_deprecation_warning if dependent == :restrict
-
- send("define_#{dependent}_dependency_method")
- model.before_destroy dependency_method_name
- end
- end
-
- def define_destroy_dependency_method
- name = self.name
- mixin.redefine_method(dependency_method_name) do
- association(name).delete
- end
- end
- alias :define_delete_dependency_method :define_destroy_dependency_method
- alias :define_nullify_dependency_method :define_destroy_dependency_method
-
- def dependency_method_name
- "has_one_dependent_#{options[:dependent]}_for_#{name}"
- end
+ def valid_dependent_options
+ [:destroy, :delete, :nullify, :restrict, :restrict_with_error, :restrict_with_exception]
+ end
end
end
diff --git a/activerecord/lib/active_record/associations/builder/singular_association.rb b/activerecord/lib/active_record/associations/builder/singular_association.rb
index 90a4b7c2ef..6a5830e57f 100644
--- a/activerecord/lib/active_record/associations/builder/singular_association.rb
+++ b/activerecord/lib/active_record/associations/builder/singular_association.rb
@@ -13,22 +13,20 @@ module ActiveRecord::Associations::Builder
define_constructors if constructable?
end
- private
-
- def define_constructors
- name = self.name
-
- mixin.redefine_method("build_#{name}") do |*params, &block|
- association(name).build(*params, &block)
+ def define_constructors
+ mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1
+ def build_#{name}(*args, &block)
+ association(:#{name}).build(*args, &block)
end
- mixin.redefine_method("create_#{name}") do |*params, &block|
- association(name).create(*params, &block)
+ def create_#{name}(*args, &block)
+ association(:#{name}).create(*args, &block)
end
- mixin.redefine_method("create_#{name}!") do |*params, &block|
- association(name).create!(*params, &block)
+ def create_#{name}!(*args, &block)
+ association(:#{name}).create!(*args, &block)
end
- end
+ CODE
+ end
end
end