diff options
author | David Heinemeier Hansson <david@loudthinking.com> | 2005-04-12 05:34:10 +0000 |
---|---|---|
committer | David Heinemeier Hansson <david@loudthinking.com> | 2005-04-12 05:34:10 +0000 |
commit | 3b9e90a4dab94d25bfa7ed5e47ca0641857ef992 (patch) | |
tree | 1bd1c5d02280f93c447d1917da98cbbdf9ab31a8 | |
parent | b59619600fbbfb2cf6d7156fb4c21bb2c0cec955 (diff) | |
download | rails-3b9e90a4dab94d25bfa7ed5e47ca0641857ef992.tar.gz rails-3b9e90a4dab94d25bfa7ed5e47ca0641857ef992.tar.bz2 rails-3b9e90a4dab94d25bfa7ed5e47ca0641857ef992.zip |
Moved build_association and create_association for has_one and belongs_to out of deprecation as they work when the association is nil unlike association.build and association.create, which require the association to be already in place #864
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@1146 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
-rw-r--r-- | activerecord/CHANGELOG | 2 | ||||
-rwxr-xr-x | activerecord/lib/active_record/associations.rb | 43 | ||||
-rw-r--r-- | activerecord/lib/active_record/associations/belongs_to_association.rb | 1 | ||||
-rw-r--r-- | activerecord/lib/active_record/deprecated_associations.rb | 20 | ||||
-rwxr-xr-x | activerecord/test/associations_test.rb | 37 | ||||
-rwxr-xr-x | activerecord/test/deprecated_associations_test.rb | 24 |
6 files changed, 71 insertions, 56 deletions
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 1d2d2b2bb1..a51ec02d00 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,7 @@ *SVN* +* Moved build_association and create_association for has_one and belongs_to out of deprecation as they work when the association is nil unlike association.build and association.create, which require the association to be already in place #864 + * Added rollbacks of transactions if they're active as the dispatcher is killed gracefully (TERM signal) #1054 [Leon Bredt] * Added quoting of column names for fixtures #997 [jcfischer@gmail.com] diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb index 9253abd14d..1b78b02e84 100755 --- a/activerecord/lib/active_record/associations.rb +++ b/activerecord/lib/active_record/associations.rb @@ -163,9 +163,11 @@ module ActiveRecord # * <tt>collection.find_all(conditions = nil, orderings = nil, limit = nil, joins = nil)</tt> - finds all associated objects responding # criteria mentioned (like in the standard find_all) and that meets the condition that it has to be associated with this object. # * <tt>collection.build(attributes = {})</tt> - returns a new object of the collection type that has been instantiated - # with +attributes+ and linked to this object through a foreign key but has not yet been saved. + # with +attributes+ and linked to this object through a foreign key but has not yet been saved. *Note:* This only works if an + # associated object already exists, not if its nil! # * <tt>collection.create(attributes = {})</tt> - returns a new object of the collection type that has been instantiated # with +attributes+ and linked to this object through a foreign key and that has already been saved (if it passed the validation). + # *Note:* This only works if an associated object already exists, not if its nil! # # Example: A Firm class declares <tt>has_many :clients</tt>, which will add: # * <tt>Firm#clients</tt> (similar to <tt>Clients.find_all "firm_id = #{id}"</tt>) @@ -250,19 +252,19 @@ module ActiveRecord # * <tt>association=(associate)</tt> - assigns the associate object, extracts the primary key, sets it as the foreign key, # and saves the associate object. # * <tt>association.nil?</tt> - returns true if there is no associated object. - # * <tt>association.build(attributes = {})</tt> - returns a new object of the associated type that has been instantiated + # * <tt>build_association(attributes = {})</tt> - returns a new object of the associated type that has been instantiated # with +attributes+ and linked to this object through a foreign key but has not yet been saved. Note: This ONLY works if # an association already exists. It will NOT work if the association is nil. - # * <tt>association.create(attributes = {})</tt> - returns a new object of the associated type that has been instantiated + # * <tt>create_association(attributes = {})</tt> - returns a new object of the associated type that has been instantiated # with +attributes+ and linked to this object through a foreign key and that has already been saved (if it passed the validation). - # Note: This ONLY works if an association already exists. It will NOT work if the association is nil. # # Example: An Account class declares <tt>has_one :beneficiary</tt>, which will add: # * <tt>Account#beneficiary</tt> (similar to <tt>Beneficiary.find_first "account_id = #{id}"</tt>) # * <tt>Account#beneficiary=(beneficiary)</tt> (similar to <tt>beneficiary.account_id = account.id; beneficiary.save</tt>) # * <tt>Account#beneficiary.nil?</tt> - # * <tt>Account#beneficiary.build</tt> (similar to <tt>Beneficiary.new("account_id" => id)</tt>) - # * <tt>Account#beneficiary.create</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save; b</tt>) + # * <tt>Account#build_beneficiary</tt> (similar to <tt>Beneficiary.new("account_id" => id)</tt>) + # * <tt>Account#create_beneficiary</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save; b</tt>) + # # The declaration can also include an options hash to specialize the behavior of the association. # # Options are: @@ -303,13 +305,13 @@ module ActiveRecord end association_accessor_methods(association_name, association_class_name, association_class_primary_key_name, options, HasOneAssociation) + association_constructor_method(:build, association_name, association_class_name, association_class_primary_key_name, options, HasOneAssociation) + association_constructor_method(:create, association_name, association_class_name, association_class_primary_key_name, options, HasOneAssociation) module_eval "before_destroy '#{association_name}.destroy unless #{association_name}.nil?'" if options[:dependent] # deprecated api deprecated_has_association_method(association_name) - deprecated_build_method("build_", association_name, association_class_name, association_class_primary_key_name) - deprecated_create_method("create_", association_name, association_class_name, association_class_primary_key_name) deprecated_association_comparison_method(association_name, association_class_name) end @@ -319,9 +321,9 @@ module ActiveRecord # * <tt>association(force_reload = false)</tt> - returns the associated object. Nil is returned if none is found. # * <tt>association=(associate)</tt> - assigns the associate object, extracts the primary key, and sets it as the foreign key. # * <tt>association.nil?</tt> - returns true if there is no associated object. - # * <tt>association.build(attributes = {})</tt> - returns a new object of the associated type that has been instantiated + # * <tt>build_association(attributes = {})</tt> - returns a new object of the associated type that has been instantiated # with +attributes+ and linked to this object through a foreign key but has not yet been saved. - # * <tt>association.create(attributes = {})</tt> - returns a new object of the associated type that has been instantiated + # * <tt>create_association(attributes = {})</tt> - returns a new object of the associated type that has been instantiated # with +attributes+ and linked to this object through a foreign key and that has already been saved (if it passed the validation). # # Example: A Post class declares <tt>belongs_to :author</tt>, which will add: @@ -329,8 +331,8 @@ module ActiveRecord # * <tt>Post#author=(author)</tt> (similar to <tt>post.author_id = author.id</tt>) # * <tt>Post#author?</tt> (similar to <tt>post.author == some_author</tt>) # * <tt>Post#author.nil?</tt> - # * <tt>Post#author.build</tt> (similar to <tt>Author.new("post_id" => id)</tt>) - # * <tt>Post#author.create</tt> (similar to <tt>b = Author.new("post_id" => id); b.save; b</tt>) + # * <tt>Post#build_author</tt> (similar to <tt>Author.new("post_id" => id)</tt>) + # * <tt>Post#create_author</tt> (similar to <tt>b = Author.new("post_id" => id); b.save; b</tt>) # The declaration can also include an options hash to specialize the behavior of the association. # # Options are: @@ -365,6 +367,8 @@ module ActiveRecord association_class_primary_key_name = options[:foreign_key] || Inflector.underscore(Inflector.demodulize(association_class_name)) + "_id" association_accessor_methods(association_name, association_class_name, association_class_primary_key_name, options, BelongsToAssociation) + association_constructor_method(:build, association_name, association_class_name, association_class_primary_key_name, options, BelongsToAssociation) + association_constructor_method(:create, association_name, association_class_name, association_class_primary_key_name, options, BelongsToAssociation) module_eval do before_save <<-EOF @@ -626,6 +630,21 @@ module ActiveRecord end end + def association_constructor_method(constructor, association_name, association_class_name, association_class_primary_key_name, options, association_proxy_class) + define_method("#{constructor}_#{association_name}") do |*params| + attributees = params.first unless params.empty? + association = instance_variable_get("@#{association_name}") + + if association.nil? + association = association_proxy_class.new(self, + association_name, association_class_name, + association_class_primary_key_name, options) + instance_variable_set("@#{association_name}", association) + end + + association.send(constructor, attributees) + end + end def find_with_associations(options = {}) reflections = reflect_on_included_associations(options[:include]) diff --git a/activerecord/lib/active_record/associations/belongs_to_association.rb b/activerecord/lib/active_record/associations/belongs_to_association.rb index 521aff4058..b142a13153 100644 --- a/activerecord/lib/active_record/associations/belongs_to_association.rb +++ b/activerecord/lib/active_record/associations/belongs_to_association.rb @@ -1,7 +1,6 @@ module ActiveRecord module Associations class BelongsToAssociation < AssociationProxy #:nodoc: - def reset @target = nil @loaded = false diff --git a/activerecord/lib/active_record/deprecated_associations.rb b/activerecord/lib/active_record/deprecated_associations.rb index a3d0f1d947..077ac1de3b 100644 --- a/activerecord/lib/active_record/deprecated_associations.rb +++ b/activerecord/lib/active_record/deprecated_associations.rb @@ -84,25 +84,7 @@ module ActiveRecord !#{association_name}(force_reload).nil? end end_eval - end - - def deprecated_build_method(method_prefix, collection_name, collection_class_name, class_primary_key_name)# :nodoc: - module_eval <<-"end_eval", __FILE__, __LINE__ - def #{method_prefix + collection_name}(attributes = {}) - association = #{collection_class_name}.new - association.attributes = attributes.merge({ "#{class_primary_key_name}" => id}) - association - end - end_eval - end - - def deprecated_create_method(method_prefix, collection_name, collection_class_name, class_primary_key_name)# :nodoc: - module_eval <<-"end_eval", __FILE__, __LINE__ - def #{method_prefix + collection_name}(attributes = nil) - #{collection_class_name}.create((attributes || {}).merge({ "#{class_primary_key_name}" => id})) - end - end_eval - end + end end end end diff --git a/activerecord/test/associations_test.rb b/activerecord/test/associations_test.rb index 71e2ab01f8..6cca750644 100755 --- a/activerecord/test/associations_test.rb +++ b/activerecord/test/associations_test.rb @@ -105,6 +105,30 @@ class HasOneAssociationsTest < Test::Unit::TestCase assert_equal 1, Account.find_all.length end + def test_succesful_build_association + firm = Firm.new("name" => "GlobalMegaCorp") + firm.save + + account = firm.build_account("credit_limit" => 1000) + assert account.save + assert_equal account, firm.account + end + + def test_failing_build_association + firm = Firm.new("name" => "GlobalMegaCorp") + firm.save + + account = firm.build_account + assert !account.save + assert_equal "can't be empty", account.errors.on("credit_limit") + end + + def test_create_association + firm = Firm.new("name" => "GlobalMegaCorp") + firm.save + assert_equal firm.create_account("credit_limit" => 1000), firm.account + end + def test_build firm = Firm.new("name" => "GlobalMegaCorp") firm.save @@ -563,6 +587,19 @@ class BelongsToAssociationsTest < Test::Unit::TestCase assert_equal apple.id, citibank.firm_id end + def test_creating_the_belonging_object + citibank = Account.create("credit_limit" => 10) + apple = citibank.create_firm("name" => "Apple") + assert_equal apple, citibank.firm + end + + def test_building_the_belonging_object + citibank = Account.create("credit_limit" => 10) + apple = citibank.build_firm("name" => "Apple") + citibank.save + assert_equal apple.id, citibank.firm_id + end + def test_natural_assignment_to_nil client = Client.find(3) client.firm = nil diff --git a/activerecord/test/deprecated_associations_test.rb b/activerecord/test/deprecated_associations_test.rb index 49387ec8dc..4c2c62b8bd 100755 --- a/activerecord/test/deprecated_associations_test.rb +++ b/activerecord/test/deprecated_associations_test.rb @@ -174,30 +174,6 @@ class DeprecatedAssociationsTest < Test::Unit::TestCase assert_equal @signals37.create_in_clients_of_firm("name" => "Another Client"), @signals37.clients_of_firm(true).last end - def test_succesful_build_association - firm = Firm.new("name" => "GlobalMegaCorp") - firm.save - - account = firm.build_account("credit_limit" => 1000) - assert account.save - assert_equal account, firm.account - end - - def test_failing_build_association - firm = Firm.new("name" => "GlobalMegaCorp") - firm.save - - account = firm.build_account - assert !account.save - assert_equal "can't be empty", account.errors.on("credit_limit") - end - - def test_create_association - firm = Firm.new("name" => "GlobalMegaCorp") - firm.save - assert_equal firm.create_account("credit_limit" => 1000), firm.account - end - def test_has_and_belongs_to_many david = Developer.find(1) assert david.has_projects? |