Permalink
Browse files

Add deprecation warning for calling .create on has_many associations …

…with an unsaved owner.

Fix regression introduced by [7076] by restoring 1.2.3 behaviour for saving associated records [Bryan Helmkamp].  References #8713


git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/1-2-stable@7823 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
1 parent 3397839 commit a692432d8a34cdebc0ea2b4a91fa79292654fe3f @NZKoz NZKoz committed Oct 10, 2007
View
15 activerecord/lib/active_record/associations.rb
@@ -994,12 +994,15 @@ def add_multiple_associated_save_callbacks(association_name)
after_callback = <<-end_eval
association = instance_variable_get("@#{association_name}")
- if association.respond_to?(:loaded?) && association.loaded?
- if @new_record_before_save
- records_to_save = association
- else
- records_to_save = association.select { |record| record.new_record? }
- end
+ records_to_save = if @new_record_before_save
+ association
+ elsif association.respond_to?(:loaded?) && association.loaded?
+ association.select { |record| record.new_record? }
+ else
+ []
+ end
+
+ if !records_to_save.blank?
records_to_save.each { |record| association.send(:insert_record, record) }
association.send(:construct_sql) # reconstruct the SQL queries now that we know the owner's id
end
View
6 activerecord/lib/active_record/associations/association_collection.rb
@@ -91,7 +91,11 @@ def create(attributes = {})
attributes.collect { |attr| create(attr) }
else
record = build(attributes)
- record.save unless @owner.new_record?
+ if @owner.new_record?
+ ActiveSupport::Deprecation.warn("Calling .create on a has_many association without saving its owner will not work in rails 2.0, you probably want .build instead")
+ else
+ record.save
+ end
record
end
end
View
12 activerecord/test/associations_test.rb
@@ -95,6 +95,11 @@ def test_save_on_parent_does_not_load_target
david.update_attribute(:created_at, Time.now)
assert !david.projects.loaded?
end
+
+ def test_save_on_parent_saves_children
+ developer = Developer.create :name => "Bryan", :salary => 50_000
+ assert_equal 1, developer.reload.audit_logs.size
+ end
end
class HasOneAssociationsTest < Test::Unit::TestCase
@@ -591,6 +596,13 @@ def test_adding_using_create
assert_equal 3, first_firm.plain_clients.size
end
+ def test_regular_create_on_has_many_when_parent_is_new_raises
+ assert_deprecated(/.build instead/) do
+ firm = Firm.new
+ firm.plain_clients.create :name=>"Whoever"
+ end
+ end
+
def test_adding_a_mismatch_class
assert_raises(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).clients_of_firm << nil }
assert_raises(ActiveRecord::AssociationTypeMismatch) { companies(:first_firm).clients_of_firm << 1 }
View
5 activerecord/test/fixtures/db_definitions/schema.rb
@@ -57,4 +57,9 @@ def create_table(*args, &block)
create_table :lock_without_defaults_cust, :force => true do |t|
t.column :custom_lock_version, :integer
end
+
+ create_table :audit_logs, :force => true do |t|
+ t.column :message, :string, :null=>false
+ t.column :developer_id, :integer, :null=>false
+ end
end
View
10 activerecord/test/fixtures/developer.rb
@@ -31,8 +31,18 @@ def find_most_recent
has_and_belongs_to_many :special_projects, :join_table => 'developers_projects', :association_foreign_key => 'project_id'
+ has_many :audit_logs
+
validates_inclusion_of :salary, :in => 50000..200000
validates_length_of :name, :within => 3..20
+
+ before_create do |developer|
+ developer.audit_logs.build :message => "Computer created"
+ end
+end
+
+class AuditLog < ActiveRecord::Base
+ belongs_to :developer
end
DeveloperSalary = Struct.new(:amount)
View
4 activerecord/test/validations_test.rb
@@ -631,7 +631,7 @@ def test_validates_size_of_association
t = Topic.new('title' => 'noreplies', 'content' => 'whatever')
assert !t.save
assert t.errors.on(:replies)
- t.replies.create('title' => 'areply', 'content' => 'whateveragain')
+ t.replies.build('title' => 'areply', 'content' => 'whateveragain')
assert t.valid?
end
@@ -824,7 +824,7 @@ def test_validates_size_of_association_utf8
t = Topic.new('title' => 'あいうえお', 'content' => 'かきくけこ')
assert !t.save
assert t.errors.on(:replies)
- t.replies.create('title' => 'あいうえお', 'content' => 'かきくけこ')
+ t.replies.build('title' => 'あいうえお', 'content' => 'かきくけこ')
assert t.valid?
end
end

0 comments on commit a692432

Please sign in to comment.