diff options
Diffstat (limited to 'activerecord/lib/active_record/associations/builder/collection_association.rb')
-rw-r--r-- | activerecord/lib/active_record/associations/builder/collection_association.rb | 87 |
1 files changed, 43 insertions, 44 deletions
diff --git a/activerecord/lib/active_record/associations/builder/collection_association.rb b/activerecord/lib/active_record/associations/builder/collection_association.rb index fdead16761..7bd0687c0b 100644 --- a/activerecord/lib/active_record/associations/builder/collection_association.rb +++ b/activerecord/lib/active_record/associations/builder/collection_association.rb @@ -1,3 +1,5 @@ +# This class is inherited by the has_many and has_many_and_belongs_to_many association classes + require 'active_record/associations' module ActiveRecord::Associations::Builder @@ -6,67 +8,54 @@ module ActiveRecord::Associations::Builder CALLBACKS = [:before_add, :after_add, :before_remove, :after_remove] def valid_options - super + [:table_name, :finder_sql, :counter_sql, :before_add, + super + [:table_name, :before_add, :after_add, :before_remove, :after_remove, :extend] end - attr_reader :block_extension, :extension_module - - def initialize(*args, &extension) - super(*args) - @block_extension = extension - end + attr_reader :block_extension - def build - show_deprecation_warnings - wrap_block_extension - reflection = super - CALLBACKS.each { |callback_name| define_callback(callback_name) } - reflection + def initialize(name, scope, options) + super + @mod = nil + if block_given? + @mod = Module.new(&Proc.new) + @scope = wrap_scope @scope, @mod + end end - def writable? - true + def define_callbacks(model, reflection) + super + CALLBACKS.each { |callback_name| define_callback(model, callback_name) } end - def show_deprecation_warnings - [:finder_sql, :counter_sql].each do |name| - if options.include? name - ActiveSupport::Deprecation.warn("The :#{name} association option is deprecated. Please find an alternative (such as using scopes).") - end + def define_extensions(model) + if @mod + extension_module_name = "#{model.name.demodulize}#{name.to_s.camelize}AssociationExtension" + model.parent.const_set(extension_module_name, @mod) end 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 + def define_callback(model, callback_name) + full_callback_name = "#{callback_name}_for_#{name}" - if prev_scope - @scope = proc { |owner| instance_exec(owner, &prev_scope).extending(mod) } + # TODO : why do i need method_defined? I think its because of the inheritance chain + model.class_attribute full_callback_name unless model.method_defined?(full_callback_name) + callbacks = Array(options[callback_name.to_sym]).map do |callback| + case callback + when Symbol + ->(method, owner, record) { owner.send(callback, record) } + when Proc + ->(method, owner, record) { callback.call(owner, record) } else - @scope = proc { extending(mod) } + ->(method, owner, record) { callback.send(method, owner, record) } end end + model.send "#{full_callback_name}=", callbacks 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}" - - # 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 + # Defines the setter and getter methods for the collection_singular_ids. - def define_readers + def define_readers(mixin) super mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1 @@ -76,7 +65,7 @@ module ActiveRecord::Associations::Builder CODE end - def define_writers + def define_writers(mixin) super mixin.class_eval <<-CODE, __FILE__, __LINE__ + 1 @@ -85,5 +74,15 @@ module ActiveRecord::Associations::Builder end CODE end + + private + + def wrap_scope(scope, mod) + if scope + proc { |owner| instance_exec(owner, &scope).extending(mod) } + else + proc { extending(mod) } + end + end end end |