diff options
Diffstat (limited to 'activerecord/lib/active_record')
-rw-r--r-- | activerecord/lib/active_record/associations.rb | 82 | ||||
-rw-r--r-- | activerecord/lib/active_record/associations/builder/association.rb | 11 |
2 files changed, 91 insertions, 2 deletions
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 33cbafc6aa..d68fb33962 100644 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -1560,8 +1560,86 @@ module ActiveRecord # has_and_belongs_to_many :categories, join_table: "prods_cats" # has_and_belongs_to_many :categories, -> { readonly } def has_and_belongs_to_many(name, scope = nil, options = {}, &extension) - reflection = Builder::HasAndBelongsToMany.build(self, name, scope, options, &extension) - Reflection.add_reflection self, name, reflection + if scope.is_a?(Hash) + options = scope + scope = nil + end + + has_and_belongs_to_many1(name, scope, options, &extension) + end + + def has_and_belongs_to_many1(name, scope = nil, options = {}, &extension) + # temporarily + habtm_builder = Builder::HasAndBelongsToMany.create_builder(self, name, scope, options, &extension) + habtm = habtm_builder.build self + + join_class_name = "HABTM_#{name.to_s.camelize}" + this_class = self + rhs_name = name.to_s.singularize.to_sym + + join_model = Class.new(ActiveRecord::Base) { + define_singleton_method(:name) { join_class_name } + define_singleton_method(:table_name) { habtm.join_table } + define_singleton_method(:compute_type) { |class_name| + this_class.compute_type class_name + } + belongs_to :left_side, :class => this_class + + rhs_options = {} + + if options.key? :class_name + rhs_options[:foreign_key] = options[:class_name].foreign_key + rhs_options[:class_name] = options[:class_name] + end + + if options.key? :association_foreign_key + rhs_options[:foreign_key] = options[:association_foreign_key] + end + + belongs_to rhs_name, rhs_options + } + + middle_name = [self.name.downcase.pluralize, name].join('_').gsub(/::/, '_').to_sym + + #middle_options = options.dup + middle_options = {} + middle_options[:class] = join_model + middle_options[:source] = :left_side + if options.key? :foreign_key + middle_options[:foreign_key] = options[:foreign_key] + end + + hm_builder = Builder::HasMany.create_builder(self, + middle_name, + nil, + middle_options) + middle_reflection = hm_builder.build self + hm_builder.define_callbacks self, middle_reflection + + Reflection.add_reflection self, middle_name, middle_reflection + + include Module.new { + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def destroy_associations + association(:#{middle_name}).delete_all(:delete_all) + association(:#{name}).reset + super + end + RUBY + } + + hm_options = {} + hm_options[:through] = middle_name + hm_options[:source] = rhs_name + + [:before_add, :after_add, :before_remove, :after_remove].each do |k| + if options.key? k + hm_options[k] = options[k] + end + end + + #has_many name, scope, :through => middle_name, &extension + has_many name, scope, hm_options, &extension end end end diff --git a/activerecord/lib/active_record/associations/builder/association.rb b/activerecord/lib/active_record/associations/builder/association.rb index 1059fc032d..6de0331851 100644 --- a/activerecord/lib/active_record/associations/builder/association.rb +++ b/activerecord/lib/active_record/associations/builder/association.rb @@ -37,6 +37,17 @@ module ActiveRecord::Associations::Builder reflection end + def self.create_builder(model, name, scope, options, &block) + raise ArgumentError, "association names must be a Symbol" unless name.kind_of?(Symbol) + + if scope.is_a?(Hash) + options = scope + scope = nil + end + + new(name, scope, options, &block) + end + def initialize(name, scope, options) @name = name @scope = scope |