Changeset 3213
- Timestamp:
- 12/03/05 04:29:55 (3 years ago)
- Files:
-
- trunk/activerecord/CHANGELOG (modified) (1 diff)
- trunk/activerecord/lib/active_record.rb (modified) (1 diff)
- trunk/activerecord/lib/active_record/aggregations.rb (modified) (2 diffs)
- trunk/activerecord/lib/active_record/associations.rb (modified) (12 diffs)
- trunk/activerecord/lib/active_record/associations/association_collection.rb (modified) (5 diffs)
- trunk/activerecord/lib/active_record/associations/association_proxy.rb (modified) (6 diffs)
- trunk/activerecord/lib/active_record/associations/belongs_to_association.rb (modified) (2 diffs)
- trunk/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb (modified) (2 diffs)
- trunk/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb (modified) (11 diffs)
- trunk/activerecord/lib/active_record/associations/has_many_association.rb (modified) (12 diffs)
- trunk/activerecord/lib/active_record/associations/has_many_through_association.rb (added)
- trunk/activerecord/lib/active_record/associations/has_one_association.rb (modified) (6 diffs)
- trunk/activerecord/lib/active_record/base.rb (modified) (2 diffs)
- trunk/activerecord/lib/active_record/reflection.rb (modified) (8 diffs)
- trunk/activerecord/test/associations_join_model_test.rb (moved) (moved from trunk/activerecord/test/associations_interface_test.rb) (1 diff)
- trunk/activerecord/test/fixtures/post.rb (modified) (1 diff)
- trunk/activerecord/test/reflection_test.rb (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/activerecord/CHANGELOG
r3206 r3213 1 1 *SVN* 2 3 * Added preliminary support for polymorphic associations [DHH] 4 5 * Added preliminary support for join models [DHH] 2 6 3 7 * Allow validate_uniqueness_of to be scoped by more than just one column. #1559. [jeremy@jthopple.com, Marcel Molina Jr.] trunk/activerecord/lib/active_record.rb
r3052 r3213 39 39 require 'active_record/validations' 40 40 require 'active_record/callbacks' 41 require 'active_record/reflection' 41 42 require 'active_record/associations' 42 43 require 'active_record/aggregations' 43 44 require 'active_record/transactions' 44 require 'active_record/reflection'45 45 require 'active_record/timestamp' 46 46 require 'active_record/acts/list' trunk/activerecord/lib/active_record/aggregations.rb
r2744 r3213 1 1 module ActiveRecord 2 2 module Aggregations # :nodoc: 3 def self.append_features(base) 4 super 3 def self.included(base) 5 4 base.extend(ClassMethods) 6 5 end … … 129 128 reader_method(name, class_name, mapping) 130 129 writer_method(name, class_name, mapping) 130 131 create_reflection(:composed_of, part_id, options, self) 131 132 end 132 133 trunk/activerecord/lib/active_record/associations.rb
r3209 r3213 5 5 require 'active_record/associations/has_one_association' 6 6 require 'active_record/associations/has_many_association' 7 require 'active_record/associations/has_many_through_association' 7 8 require 'active_record/associations/has_and_belongs_to_many_association' 8 9 require 'active_record/deprecated_associations' … … 342 343 # 'ORDER BY p.first_name' 343 344 def has_many(association_id, options = {}, &extension) 344 options.assert_valid_keys( 345 :foreign_key, :class_name, :exclusively_dependent, :dependent, 346 :conditions, :order, :include, :finder_sql, :counter_sql, 347 :before_add, :after_add, :before_remove, :after_remove, :extend, 348 :group, :as 349 ) 350 351 options[:extend] = create_extension_module(association_id, extension) if block_given? 352 353 association_name, association_class_name, association_class_primary_key_name = 354 associate_identification(association_id, options[:class_name], options[:foreign_key]) 355 356 require_association_class(association_class_name) 357 358 raise ArgumentError, ':dependent and :exclusively_dependent are mutually exclusive options. You may specify one or the other.' if options[:dependent] and options[:exclusively_dependent] 359 360 if options[:exclusively_dependent] 361 options[:dependent] = :delete_all 362 #warn "The :exclusively_dependent option is deprecated. Please use :dependent => :delete_all instead.") 363 end 364 365 # See HasManyAssociation#delete_records. Dependent associations 366 # delete children, otherwise foreign key is set to NULL. 367 case options[:dependent] 368 when :destroy, true 369 module_eval "before_destroy '#{association_name}.each { |o| o.destroy }'" 370 when :delete_all 371 module_eval "before_destroy { |record| #{association_class_name}.delete_all(%(#{association_class_primary_key_name} = \#{record.quoted_id})) }" 372 when :nullify 373 module_eval "before_destroy { |record| #{association_class_name}.update_all(%(#{association_class_primary_key_name} = NULL), %(#{association_class_primary_key_name} = \#{record.quoted_id})) }" 374 when nil, false 375 # pass 376 else 377 raise ArgumentError, 'The :dependent option expects either true, :destroy, :delete_all, or :nullify' 378 end 379 380 381 add_multiple_associated_save_callbacks(association_name) 382 add_association_callbacks(association_name, options) 383 384 collection_accessor_methods(association_name, association_class_name, association_class_primary_key_name, options, HasManyAssociation) 385 386 # deprecated api 387 deprecated_collection_count_method(association_name) 388 deprecated_add_association_relation(association_name) 389 deprecated_remove_association_relation(association_name) 390 deprecated_has_collection_method(association_name) 391 deprecated_find_in_collection_method(association_name) 392 deprecated_find_all_in_collection_method(association_name) 393 deprecated_collection_create_method(association_name) 394 deprecated_collection_build_method(association_name) 345 reflection = create_has_many_reflection(association_id, options, &extension) 346 347 configure_dependency_for_has_many(reflection) 348 349 if options[:through] 350 collection_reader_method(reflection, HasManyThroughAssociation) 351 else 352 add_multiple_associated_save_callbacks(reflection.name) 353 add_association_callbacks(reflection.name, reflection.options) 354 collection_accessor_methods(reflection, HasManyAssociation) 355 end 356 357 add_deprecated_api_for_has_many(reflection.name) 395 358 end 396 359 … … 437 400 # has_one :project_manager, :class_name => "Person", :conditions => "role = 'project_manager'" 438 401 def has_one(association_id, options = {}) 439 options.assert_valid_keys(:class_name, :foreign_key, :remote, :conditions, :order, :include, :dependent, :counter_cache, :extend) 440 441 association_name, association_class_name, association_class_primary_key_name = 442 associate_identification(association_id, options[:class_name], options[:foreign_key], false) 443 444 require_association_class(association_class_name) 402 reflection = create_has_one_reflection(association_id, options) 445 403 446 404 module_eval do 447 405 after_save <<-EOF 448 association = instance_variable_get("@#{ association_name}")406 association = instance_variable_get("@#{reflection.name}") 449 407 unless association.nil? 450 association["#{ association_class_primary_key_name}"] = id408 association["#{reflection.primary_key_name}"] = id 451 409 association.save(true) 452 association.send(:construct_sql)453 410 end 454 411 EOF 455 412 end 456 413 457 association_accessor_methods( association_name, association_class_name, association_class_primary_key_name, options, HasOneAssociation)458 association_constructor_method(:build, association_name, association_class_name, association_class_primary_key_name, options, HasOneAssociation)459 association_constructor_method(:create, association_name, association_class_name, association_class_primary_key_name, options, HasOneAssociation)414 association_accessor_methods(reflection, HasOneAssociation) 415 association_constructor_method(:build, reflection, HasOneAssociation) 416 association_constructor_method(:create, reflection, HasOneAssociation) 460 417 461 case options[:dependent] 462 when :destroy, true 463 module_eval "before_destroy '#{association_name}.destroy unless #{association_name}.nil?'" 464 when :nullify 465 module_eval "before_destroy '#{association_name}.update_attribute(\"#{association_class_primary_key_name}\", nil)'" 466 when nil, false 467 # pass 468 else 469 raise ArgumentError, "The :dependent option expects either :destroy or :nullify." 470 end 418 configure_dependency_for_has_one(reflection) 471 419 472 420 # deprecated api 473 deprecated_has_association_method( association_name)474 deprecated_association_comparison_method( association_name, association_class_name)421 deprecated_has_association_method(reflection.name) 422 deprecated_association_comparison_method(reflection.name, reflection.class_name) 475 423 end 476 424 … … 518 466 # :conditions => 'discounts > #{payments_count}' 519 467 def belongs_to(association_id, options = {}) 520 options.assert_valid_keys(:class_name, :foreign_key, :foreign_type, :remote, :conditions, :order, :include, :dependent, :counter_cache, :extend, :polymorphic) 521 522 association_name, association_class_name, class_primary_key_name = 523 associate_identification(association_id, options[:class_name], options[:foreign_key], false) 524 525 association_class_primary_key_name = options[:foreign_key] || association_class_name.foreign_key 526 527 if options[:polymorphic] 528 options[:foreign_type] ||= association_class_name.underscore + "_type" 529 530 association_accessor_methods(association_name, association_class_name, association_class_primary_key_name, options, BelongsToPolymorphicAssociation) 468 reflection = create_belongs_to_reflection(association_id, options) 469 470 if reflection.options[:polymorphic] 471 association_accessor_methods(reflection, BelongsToPolymorphicAssociation) 531 472 532 473 module_eval do 533 474 before_save <<-EOF 534 association = instance_variable_get("@#{ association_name}")475 association = instance_variable_get("@#{reflection.name}") 535 476 if !association.nil? 536 477 if association.new_record? 537 478 association.save(true) 538 association.send(:construct_sql)539 479 end 540 480 541 481 if association.updated? 542 self["#{ association_class_primary_key_name}"] = association.id543 self["#{ options[:foreign_type]}"] = ActiveRecord::Base.send(:class_name_of_active_record_descendant, association.class).to_s482 self["#{reflection.primary_key_name}"] = association.id 483 self["#{reflection.options[:foreign_type]}"] = ActiveRecord::Base.send(:class_name_of_active_record_descendant, association.class).to_s 544 484 end 545 485 end … … 547 487 end 548 488 else 549 require_association_class(association_class_name) 550 551 association_accessor_methods(association_name, association_class_name, association_class_primary_key_name, options, BelongsToAssociation) 552 association_constructor_method(:build, association_name, association_class_name, association_class_primary_key_name, options, BelongsToAssociation) 553 association_constructor_method(:create, association_name, association_class_name, association_class_primary_key_name, options, BelongsToAssociation) 489 association_accessor_methods(reflection, BelongsToAssociation) 490 association_constructor_method(:build, reflection, BelongsToAssociation) 491 association_constructor_method(:create, reflection, BelongsToAssociation) 554 492 555 493 module_eval do 556 494 before_save <<-EOF 557 association = instance_variable_get("@#{ association_name}")495 association = instance_variable_get("@#{reflection.name}") 558 496 if !association.nil? 559 497 if association.new_record? 560 498 association.save(true) 561 association.send(:construct_sql)562 499 end 563 500 564 501 if association.updated? 565 self["#{ association_class_primary_key_name}"] = association.id502 self["#{reflection.primary_key_name}"] = association.id 566 503 end 567 504 end … … 571 508 if options[:counter_cache] 572 509 module_eval( 573 "after_create '#{ association_class_name}.increment_counter(\"#{self.to_s.underscore.pluralize + "_count"}\", #{association_class_primary_key_name})" +574 " unless #{ association_name}.nil?'"510 "after_create '#{reflection.class_name}.increment_counter(\"#{self.to_s.underscore.pluralize + "_count"}\", #{reflection.primary_key_name})" + 511 " unless #{reflection.name}.nil?'" 575 512 ) 576 513 577 514 module_eval( 578 "before_destroy '#{ association_class_name}.decrement_counter(\"#{self.to_s.underscore.pluralize + "_count"}\", #{association_class_primary_key_name})" +579 " unless #{ association_name}.nil?'"515 "before_destroy '#{reflection.class_name}.decrement_counter(\"#{self.to_s.underscore.pluralize + "_count"}\", #{reflection.primary_key_name})" + 516 " unless #{reflection.name}.nil?'" 580 517 ) 581 518 end 582 519 583 520 # deprecated api 584 deprecated_has_association_method( association_name)585 deprecated_association_comparison_method( association_name, association_class_name)521 deprecated_has_association_method(reflection.name) 522 deprecated_association_comparison_method(reflection.name, reflection.class_name) 586 523 end 587 524 end … … 664 601 # 'DELETE FROM developers_projects WHERE active=1 AND developer_id = #{id} AND project_id = #{record.id}' 665 602 def has_and_belongs_to_many(association_id, options = {}, &extension) 666 options.assert_valid_keys( 667 :class_name, :table_name, :foreign_key, :association_foreign_key, :conditions, :include, 668 :join_table, :finder_sql, :delete_sql, :insert_sql, :order, :uniq, :before_add, :after_add, 669 :before_remove, :after_remove, :extend 670 ) 671 672 options[:extend] = create_extension_module(association_id, extension) if block_given? 673 674 association_name, association_class_name, association_class_primary_key_name = 675 associate_identification(association_id, options[:class_name], options[:foreign_key]) 676 677 require_association_class(association_class_name) 678 679 options[:join_table] ||= join_table_name(undecorated_table_name(self.to_s), undecorated_table_name(association_class_name)) 680 681 add_multiple_associated_save_callbacks(association_name) 682 683 collection_accessor_methods(association_name, association_class_name, association_class_primary_key_name, options, HasAndBelongsToManyAssociation) 603 reflection = create_has_and_belongs_to_many_reflection(association_id, options, &extension) 604 605 add_multiple_associated_save_callbacks(reflection.name) 606 collection_accessor_methods(reflection, HasAndBelongsToManyAssociation) 684 607 685 608 # Don't use a before_destroy callback since users' before_destroy 686 609 # callbacks will be executed after the association is wiped out. 687 old_method = "destroy_without_habtm_shim_for_#{ association_name}"610 old_method = "destroy_without_habtm_shim_for_#{reflection.name}" 688 611 class_eval <<-end_eval 689 612 alias_method :#{old_method}, :destroy_without_callbacks 690 613 def destroy_without_callbacks 691 #{ association_name}.clear614 #{reflection.name}.clear 692 615 #{old_method} 693 616 end 694 617 end_eval 695 618 696 add_association_callbacks( association_name, options)619 add_association_callbacks(reflection.name, options) 697 620 698 621 # deprecated api 699 deprecated_collection_count_method( association_name)700 deprecated_add_association_relation( association_name)701 deprecated_remove_association_relation( association_name)702 deprecated_has_collection_method( association_name)622 deprecated_collection_count_method(reflection.name) 623 deprecated_add_association_relation(reflection.name) 624 deprecated_remove_association_relation(reflection.name) 625 deprecated_has_collection_method(reflection.name) 703 626 end 704 627 … … 714 637 end 715 638 716 def associate_identification(association_id, association_class_name, foreign_key, plural = true) 717 if association_class_name !~ /::/ 718 association_class_name = type_name_with_module( 719 association_class_name || 720 Inflector.camelize(plural ? Inflector.singularize(association_id.id2name) : association_id.id2name) 721 ) 722 end 723 724 primary_key_name = foreign_key || name.foreign_key 725 726 return association_id.id2name, association_class_name, primary_key_name 727 end 728 729 def association_accessor_methods(association_name, association_class_name, association_class_primary_key_name, options, association_proxy_class) 730 define_method(association_name) do |*params| 639 def association_accessor_methods(reflection, association_proxy_class) 640 define_method(reflection.name) do |*params| 731 641 force_reload = params.first unless params.empty? 732 association = instance_variable_get("@#{association_name}") 733 if association.nil? or force_reload 734 association = association_proxy_class.new(self, 735 association_name, association_class_name, 736 association_class_primary_key_name, options) 642 association = instance_variable_get("@#{reflection.name}") 643 644 if association.nil? || force_reload 645 association = association_proxy_class.new(self, reflection) 737 646 retval = association.reload 738 647 unless retval.nil? 739 instance_variable_set("@#{ association_name}", association)648 instance_variable_set("@#{reflection.name}", association) 740 649 else 741 instance_variable_set("@#{ association_name}", nil)650 instance_variable_set("@#{reflection.name}", nil) 742 651 return nil 743 652 end … … 746 655 end 747 656 748 define_method("#{ association_name}=") do |new_value|749 association = instance_variable_get("@#{ association_name}")657 define_method("#{reflection.name}=") do |new_value| 658 association = instance_variable_get("@#{reflection.name}") 750 659 if association.nil? 751 association = association_proxy_class.new(self, 752 association_name, association_class_name, 753 association_class_primary_key_name, options) 660 association = association_proxy_class.new(self, reflection) 754 661 end 662 755 663 association.replace(new_value) 664 756 665 unless new_value.nil? 757 instance_variable_set("@#{ association_name}", association)666 instance_variable_set("@#{reflection.name}", association) 758 667 else 759 instance_variable_set("@#{ association_name}", nil)668 instance_variable_set("@#{reflection.name}", nil) 760 669 return nil 761 670 end 671 762 672 association 763 673 end 764 674 765 define_method("set_#{ association_name}_target") do |target|675 define_method("set_#{reflection.name}_target") do |target| 766 676 return if target.nil? 767 association = association_proxy_class.new(self, 768 association_name, association_class_name, 769 association_class_primary_key_name, options) 677 association = association_proxy_class.new(self, reflection) 770 678 association.target = target 771 instance_variable_set("@#{ association_name}", association)772 end 773 end 774 775 def collection_ accessor_methods(association_name, association_class_name, association_class_primary_key_name, options, association_proxy_class)776 define_method( association_name) do |*params|679 instance_variable_set("@#{reflection.name}", association) 680 end 681 end 682 683 def collection_reader_method(reflection, association_proxy_class) 684 define_method(reflection.name) do |*params| 777 685 force_reload = params.first unless params.empty? 778 association = instance_variable_get("@#{association_name}") 686 association = instance_variable_get("@#{reflection.name}") 687 779 688 unless association.respond_to?(:loaded?) 780 association = association_proxy_class.new(self, 781 association_name, association_class_name, 782 association_class_primary_key_name, options) 783 instance_variable_set("@#{association_name}", association) 689 association = association_proxy_class.new(self, reflection) 690 instance_variable_set("@#{reflection.name}", association) 784 691 end 692 785 693 association.reload if force_reload 694 786 695 association 787 696 end 788 789 define_method("#{association_name}=") do |new_value| 790 association = instance_variable_get("@#{association_name}") 697 end 698 699 def collection_accessor_methods(reflection, association_proxy_class) 700 collection_reader_method(reflection, association_proxy_class) 701 702 define_method("#{reflection.name}=") do |new_value| 703 association = instance_variable_get("@#{reflection.name}") 791 704 unless association.respond_to?(:loaded?) 792 association = association_proxy_class.new(self, 793 association_name, association_class_name, 794 association_class_primary_key_name, options) 795 instance_variable_set("@#{association_name}", association) 705 association = association_proxy_class.new(self, reflection) 706 instance_variable_set("@#{reflection.name}", association) 796 707 end 797 708 association.replace(new_value) … … 799 710 end 800 711 801 define_method("#{ Inflector.singularize(association_name)}_ids=") do |new_value|802 send("#{ association_name}=", association_class_name.constantize.find(new_value))712 define_method("#{reflection.name.to_s.singularize}_ids=") do |new_value| 713 send("#{reflection.name}=", reflection.class_name.constantize.find(new_value)) 803 714 end 804 715 end … … 848 759 end 849 760 850 def association_constructor_method(constructor, association_name, association_class_name, association_class_primary_key_name, options, association_proxy_class)851 define_method("#{constructor}_#{ association_name}") do |*params|761 def association_constructor_method(constructor, reflection, association_proxy_class) 762 define_method("#{constructor}_#{reflection.name}") do |*params| 852 763 attributees = params.first unless params.empty? 853 764 replace_existing = params[1].nil? ? true : params[1] 854 association = instance_variable_get("@#{ association_name}")765 association = instance_variable_get("@#{reflection.name}") 855 766 856 767 if association.nil? 857 association = association_proxy_class.new(self, 858 association_name, association_class_name, 859 association_class_primary_key_name, options) 860 instance_variable_set("@#{association_name}", association) 768 association = association_proxy_class.new(self, reflection) 769 instance_variable_set("@#{reflection.name}", association) 861 770 end 862 771 … … 910 819 end 911 820 821 822 def configure_dependency_for_has_many(reflection) 823 if reflection.options[:dependent] && reflection.options[:exclusively_dependent] 824 raise ArgumentError, ':dependent and :exclusively_dependent are mutually exclusive options. You may specify one or the other.' 825 end 826 827 if reflection.options[:exclusively_dependent] 828 reflection.options[:dependent] = :delete_all 829 #warn "The :exclusively_dependent option is deprecated. Please use :dependent => :delete_all instead.") 830 end 831 832 # See HasManyAssociation#delete_records. Dependent associations 833 # delete children, otherwise foreign key is set to NULL. 834 case reflection.options[:dependent] 835 when :destroy, true 836 module_eval "before_destroy '#{reflection.name}.each { |o| o.destroy }'" 837 when :delete_all 838 module_eval "before_destroy { |record| #{reflection.class_name}.delete_all(%(#{reflection.primary_key_name} = \#{record.quoted_id})) }" 839 when :nullify 840 module_eval "before_destroy { |record| #{reflection.class_name}.update_all(%(#{reflection.primary_key_name} = NULL), %(#{reflection.primary_key_name} = \#{record.quoted_id})) }" 841 when nil, false 842 # pass 843 else 844 raise ArgumentError, 'The :dependent option expects either true, :destroy, :delete_all, or :nullify' 845 end 846 end 847 848 def configure_dependency_for_has_one(reflection) 849 case reflection.options[:dependent] 850 when :destroy, true 851 module_eval "before_destroy '#{reflection.name}.destroy unless #{reflection.name}.nil?'" 852 when :nullify 853 module_eval "before_destroy '#{reflection.name}.update_attribute(\"#{reflection.primary_key_name}\", nil)'" 854 when nil, false 855 # pass 856 else 857 raise ArgumentError, "The :dependent option expects either :destroy or :nullify." 858 end 859 end 860 861 862 def add_deprecated_api_for_has_many(association_name) 863 deprecated_collection_count_method(association_name) 864 deprecated_add_association_relation(association_name) 865 deprecated_remove_association_relation(association_name) 866 deprecated_has_collection_method(association_name) 867 deprecated_find_in_collection_method(association_name) 868 deprecated_find_all_in_collection_method(association_name) 869 deprecated_collection_create_method(association_name) 870 deprecated_collection_build_method(association_name) 871 end 872 873 def create_has_many_reflection(association_id, options, &extension) 874 options.assert_valid_keys( 875 :foreign_key, :class_name, :exclusively_dependent, :dependent, 876 :conditions, :order, :include, :finder_sql, :counter_sql, 877 :before_add, :after_add, :before_remove, :after_remove, :extend, 878 :group, :as, :through 879 ) 880 881 options[:extend] = create_extension_module(association_id, extension) if block_given? 882 883 reflection = create_reflection(:has_many, association_id, options, self) 884 reflection.require_class 885 886 reflection 887 end 888 889 def create_has_one_reflection(association_id, options) 890 options.assert_valid_keys( 891 :class_name, :foreign_key, :remote, :conditions, :order, :include, :dependent, :counter_cache, :extend 892 ) 893 894 reflection = create_reflection(:has_one, association_id, options, self) 895 reflection.require_class 896 897 reflection 898 end 899 900 def create_belongs_to_reflection(association_id, options) 901 options.assert_valid_keys( 902 :class_name, :foreign_key, :foreign_type, :remote, :conditions, :order, :include, :dependent, 903 :counter_cache, :extend, :polymorphic 904 ) 905 906 reflection = create_reflection(:belongs_to, association_id, options, self) 907 908 if options[:polymorphic] 909 reflection.options[:foreign_type] ||= reflection.class_name.underscore + "_type" 910 else 911 reflection.require_class 912 end 913 914 reflection 915 end 916 917 def create_has_and_belongs_to_many_reflection(association_id, options, &extension) 918 options.assert_valid_keys( 919 :class_name, :table_name, :foreign_key, :association_foreign_key, :conditions, :include, 920 :join_table, :finder_sql, :delete_sql, :insert_sql, :order, :uniq, :before_add, :after_add, 921 :before_remove, :after_remove, :extend 922 ) 923 924 options[:extend] = create_extension_module(association_id, extension) if block_given? 925 926 reflection = create_reflection(:has_and_belongs_to_many, association_id, options, self) 927 reflection.require_class 928 929 reflection.options[:join_table] ||= join_table_name(undecorated_table_name(self.to_s), undecorated_table_name(reflection.class_name)) 930 931 reflection 932 end 912 933 913 934 def reflect_on_included_associations(associations) trunk/activerecord/lib/active_record/associations/association_collection.rb
r2872 r3213 19 19 result = true 20 20 load_target 21 21 22 @owner.transaction do 22 23 flatten_deeper(records).each do |record| … … 29 30 end 30 31 31 result andself32 result && self 32 33 end 33 34 … … 61 62 def clear 62 63 return self if length.zero? # forces load_target if hasn't happened already 63 if @options[:exclusively_dependent] 64 65 if @reflection.options[:exclusively_dependent] 64 66 destroy_all 65 67 else 66 68 delete_all 67 69 end 70 68 71 self 69 72 end … … 125 128 126 129 private 127 def raise_on_type_mismatch(record)128 raise ActiveRecord::AssociationTypeMismatch, "#{@association_class} expected, got #{record.class}" unless record.is_a?(@association_class)129 end130 131 def target_obsolete?132 false133 end134 135 130 # Array#flatten has problems with recursive arrays. Going one level deeper solves the majority of the problems. 136 131 def flatten_deeper(array) … … 156 151 157 152 def callbacks_for(callback_name) 158 full_callback_name = "#{callback_name .to_s}_for_#{@association_name.to_s}"159 @owner.class.read_inheritable_attribute(full_callback_name.to_sym) or[]153 full_callback_name = "#{callback_name}_for_#{@reflection.name}" 154 @owner.class.read_inheritable_attribute(full_callback_name.to_sym) || [] 160 155 end 161 156 trunk/activerecord/lib/active_record/associations/association_proxy.rb
r3209 r3213 6 6 instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?|^proxy_respond_to\?|^proxy_extend|^send)/ } 7 7 8 def initialize(owner, association_name, association_class_name, association_class_primary_key_name, options) 9 @owner = owner 10 @options = options 11 @association_name = association_name 12 @association_class = eval(association_class_name, nil, __FILE__, __LINE__) 13 @association_class_primary_key_name = association_class_primary_key_name 14 15 proxy_extend(options[:extend]) if options[:extend] 16 8 def initialize(owner, reflection) 9 @owner, @reflection = owner, reflection 10 proxy_extend(reflection.options[:extend]) if reflection.options[:extend] 17 11 reset 18 12 end … … 27 21 load_target 28 22 other === @target 23 end 24 25 def reset 26 @target = nil 27 @loaded = false 29 28 end 30 29 … … 46 45 end 47 46 48 def target=(t )49 @target = t 50 @loaded = true47 def target=(target) 48 @target = target 49 loaded 51 50 end 52 51 53 52 protected 54 53 def dependent? 55 @ options[:dependent] || false54 @reflection.options[:dependent] || false 56 55 end 57 56 … … 69 68 70 69 def sanitize_sql(sql) 71 @ association_class.send(:sanitize_sql, sql)70 @reflection.klass.send(:sanitize_sql, sql) 72 71 end 73 72 … … 85 84 if !@owner.new_record? || foreign_key_present 86 85 begin 87 @target = find_target if notloaded?86 @target = find_target if !loaded? 88 87 rescue ActiveRecord::RecordNotFound 89 88 reset 90 89 end 91 90 end 92 @loaded = true if @target 93 @target 91 92 loaded if target 93 target 94 94 end 95 95 … … 101 101 102 102 def raise_on_type_mismatch(record) 103 raise ActiveRecord::AssociationTypeMismatch, "#{@association_class} expected, got #{record.class}" unless record.is_a?(@association_class) 103 unless record.is_a?(@reflection.klass) 104 raise ActiveRecord::AssociationTypeMismatch, "#{@reflection.class_name} expected, got #{record.class}" 105 end 104 106 end 105 107 end trunk/activerecord/lib/active_record/associations/belongs_to_association.rb
r3209 r3213 2 2 module Associations 3 3 class BelongsToAssociation < AssociationProxy #:nodoc: 4 def initialize(owner, association_name, association_class_name, association_class_primary_key_name, options)5 super6 construct_sql7 end8 9 def reset10 @target = nil11 @loaded = false12 end13 14 4 def create(attributes = {}) 15 record = @association_class.create(attributes) 16 replace(record, true) 17 record 5 replace(@reflection.klass.create(attributes)) 18 6 end 19 7 20 8 def build(attributes = {}) 21 record = @association_class.new(attributes) 22 replace(record, true) 23 record 9 replace(@reflection.klass.new(attributes)) 24 10 end 25 11 26 def replace( obj, dont_save = false)27 if obj.nil?28 @target = @owner[@ association_class_primary_key_name] = nil12 def replace(record) 13 if record.nil? 14 @target = @owner[@reflection.primary_key_name] = nil 29 15 else 30 raise_on_type_mismatch( obj) unless obj.nil?16 raise_on_type_mismatch(record) 31 17 32 @target = (AssociationProxy === obj ? obj.target : obj)33 @owner[@ association_class_primary_key_name] = obj.id unless obj.new_record?18 @target = (AssociationProxy === record ? record.target : record) 19 @owner[@reflection.primary_key_name] = record.id unless record.new_record? 34 20 @updated = true 35 21 end 36 @loaded = true37 22 38 return (@target.nil? ? nil : self) 23 loaded 24 record 39 25 end 40 26 … … 45 31 private 46 32 def find_target 47 if @options[:conditions] 48 @association_class.find( 49 @owner[@association_class_primary_key_name], 50 :conditions => interpolate_sql(@options[:conditions]), 51 :include => @options[:include] 52 ) 53 else 54 @association_class.find(@owner[@association_class_primary_key_name], :include => @options[:include]) 55 end 33 @reflection.klass.find( 34 @owner[@reflection.primary_key_name], 35 :conditions => @reflection.options[:conditions] ? interpolate_sql(@reflection.options[:conditions]) : nil, 36 :include => @reflection.options[:include] 37 ) 56 38 end 57 39 58 40 def foreign_key_present 59 !@owner[@association_class_primary_key_name].nil? 60 end 61 62 def target_obsolete? 63 @owner[@association_class_primary_key_name] != @target.id 64 end 65 66 def construct_sql 67 @finder_sql = "#{@association_class.table_name}.#{@association_class.primary_key} = #{@owner.id}" 41 !@owner[@reflection.primary_key_name].nil? 68 42 end 69 43 end trunk/activerecord/lib/active_record/associations/belongs_to_polymorphic_association.rb
r3209 r3213 1 1 module ActiveRecord 2 2 module Associations 3 class BelongsToPolymorphicAssociation < BelongsToAssociation#:nodoc:4 def initialize(owner, association_name, association_class_name, association_class_primary_key_name, options)5 @owner = owner6 @options = options7 @association_name = association_name8 @association_class_primary_key_name = association_class_primary_key_name3 class BelongsToPolymorphicAssociation < AssociationProxy #:nodoc: 4 def replace(record) 5 if record.nil? 6 @target = @owner[@reflection.primary_key_name] = @owner[@reflection.options[:foreign_type]] = nil 7 else 8 @target = (AssociationProxy === record ? record.target : record) 9 9 10 proxy_extend(options[:extend]) if options[:extend] 11 12 reset 13 end 14 15 def create(attributes = {}) 16 raise ActiveRecord::ActiveRecordError, "Can't create an abstract polymorphic object" 17 end 18 19 def build(attributes = {}) 20 raise ActiveRecord::ActiveRecordError, "Can't build an abstract polymorphic object" 21 end 22 23 def replace(obj, dont_save = false) 24 if obj.nil? 25 @target = @owner[@association_class_primary_key_name] = @owner[@options[:foreign_type]] = nil 26 else 27 @target = (AssociationProxy === obj ? obj.target : obj) 28 29 unless obj.new_record? 30 @owner[@association_class_primary_key_name] = obj.id 31 @owner[@options[:foreign_type]] = ActiveRecord::Base.send(:class_name_of_active_record_descendant, obj.class).to_s 10 unless record.new_record? 11 @owner[@reflection.primary_key_name] = record.id 12 @owner[@reflect