Changeset 7935
- Timestamp:
- 10/16/07 05:07:58 (11 months ago)
- Files:
-
- trunk/activerecord/CHANGELOG (modified) (1 diff)
- trunk/activerecord/lib/active_record/associations/association_collection.rb (modified) (2 diffs)
- trunk/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb (modified) (2 diffs)
- trunk/activerecord/lib/active_record/associations/has_many_association.rb (modified) (1 diff)
- trunk/activerecord/test/associations_test.rb (modified) (1 diff)
- trunk/activerecord/test/associations/callbacks_test.rb (modified) (2 diffs)
- trunk/activerecord/test/fixtures/author.rb (modified) (2 diffs)
- trunk/activerecord/test/fixtures/project.rb (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/activerecord/CHANGELOG
r7932 r7935 1 1 *SVN* 2 3 * Refactor association create and build so before & after callbacks behave consistently. #8854 [lifofifo, mortent] 2 4 3 5 * Quote table names. Defaults to column quoting. #4593 [Justin Lynn, gwcoffey, eadz, Dmitry V. Sabanin, Jeremy Kemper] trunk/activerecord/lib/active_record/associations/association_collection.rb
r7767 r7935 86 86 87 87 def create(attrs = {}) 88 ensure_owner_is_not_new89 record = @reflection.klass.send(:with_scope, :create => construct_scope[:create]) { @reflection.klass.create(attrs) }90 @target ||= [] unless loaded?91 @target << record92 record88 if attrs.is_a?(Array) 89 attrs.collect { |attr| create(attr) } 90 else 91 create_record(attrs) { |record| record.save } 92 end 93 93 end 94 94 95 95 def create!(attrs = {}) 96 ensure_owner_is_not_new 97 record = @reflection.klass.send(:with_scope, :create => construct_scope[:create]) { @reflection.klass.create!(attrs) } 98 @target ||= [] unless loaded? 99 @target << record 100 record 96 create_record(attrs) { |record| record.save! } 101 97 end 102 98 … … 190 186 191 187 private 188 189 def create_record(attrs, &block) 190 ensure_owner_is_not_new 191 record = @reflection.klass.send(:with_scope, :create => construct_scope[:create]) { @reflection.klass.new(attrs) } 192 add_record_to_target_with_callbacks(record, &block) 193 end 194 195 def build_record(attrs, &block) 196 record = @reflection.klass.new(attrs) 197 add_record_to_target_with_callbacks(record, &block) 198 end 199 200 def add_record_to_target_with_callbacks(record) 201 callback(:before_add, record) 202 yield(record) if block_given? 203 @target ||= [] unless loaded? 204 @target << record 205 callback(:after_add, record) 206 record 207 end 208 192 209 def callback(method, record) 193 210 callbacks_for(method).each do |callback| trunk/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb
r7666 r7935 9 9 def build(attributes = {}) 10 10 load_target 11 record = @reflection.klass.new(attributes) 12 @target << record 13 record 11 build_record(attributes) 14 12 end 15 13 16 14 def create(attributes = {}) 17 # Can't use Base.create because the foreign key may be a protected attribute. 18 ensure_owner_is_not_new 19 if attributes.is_a?(Array) 20 attributes.collect { |attr| create(attr) } 21 else 22 record = build(attributes) 23 insert_record(record) unless @owner.new_record? 24 record 25 end 15 create_record(attributes) { |record| insert_record(record) } 26 16 end 27 17 28 18 def create!(attributes = {}) 29 # Can't use Base.create! because the foreign key may be a protected attribute. 30 ensure_owner_is_not_new 31 if attributes.is_a?(Array) 32 attributes.collect { |attr| create(attr) } 33 else 34 record = build(attributes) 35 insert_record(record, true) unless @owner.new_record? 36 record 37 end 19 create_record(attributes) { |record| insert_record(record, true) } 38 20 end 39 21 … … 161 143 !select_clause && @owner.connection.columns(@reflection.options[:join_table], "Join Table Columns").size != 2 162 144 end 145 146 private 147 def create_record(attributes) 148 # Can't use Base.create because the foreign key may be a protected attribute. 149 ensure_owner_is_not_new 150 if attributes.is_a?(Array) 151 attributes.collect { |attr| create(attr) } 152 else 153 record = build(attributes) 154 yield(record) 155 record 156 end 157 end 163 158 end 164 159 end trunk/activerecord/lib/active_record/associations/has_many_association.rb
r7554 r7935 11 11 attributes.collect { |attr| build(attr) } 12 12 else 13 record = @reflection.klass.new(attributes) 14 set_belongs_to_association_for(record) 15 16 @target ||= [] unless loaded? 17 @target << record 18 19 record 13 build_record(attributes) { |record| set_belongs_to_association_for(record) } 20 14 end 21 15 end trunk/activerecord/test/associations_test.rb
r7824 r7935 596 596 end 597 597 598 def test_create_with_bang_on_has_many_raises_when_record_not_saved 599 assert_raises(ActiveRecord::RecordInvalid) do 600 firm = Firm.find(:first) 601 firm.plain_clients.create! 602 end 603 end 604 598 605 def test_create_with_bang_on_habtm_when_parent_is_new_raises 599 606 assert_raises(ActiveRecord::RecordNotSaved) do trunk/activerecord/test/associations/callbacks_test.rb
r6997 r7935 61 61 end 62 62 63 def test_has_many_callbacks_with_create 64 morten = Author.create :name => "Morten" 65 post = morten.posts_with_proc_callbacks.create! :title => "Hello", :body => "How are you doing?" 66 assert_equal ["before_adding<new>", "after_adding#{post.id}"], morten.post_log 67 end 68 69 def test_has_many_callbacks_with_create! 70 morten = Author.create! :name => "Morten" 71 post = morten.posts_with_proc_callbacks.create :title => "Hello", :body => "How are you doing?" 72 assert_equal ["before_adding<new>", "after_adding#{post.id}"], morten.post_log 73 end 74 75 def test_has_many_callbacks_for_save_on_parent 76 jack = Author.new :name => "Jack" 77 post = jack.posts_with_callbacks.build :title => "Call me back!", :body => "Before you wake up and after you sleep" 78 79 callback_log = ["before_adding<new>", "after_adding#{jack.posts_with_callbacks.first.id}"] 80 assert_equal callback_log, jack.post_log 81 assert jack.save 82 assert_equal 1, jack.posts_with_callbacks.count 83 assert_equal callback_log, jack.post_log 84 end 85 63 86 def test_has_and_belongs_to_many_add_callback 64 87 david = developers(:david) … … 99 122 end 100 123 124 def test_has_many_and_belongs_to_many_callbacks_for_save_on_parent 125 project = Project.new :name => "Callbacks" 126 project.developers_with_callbacks.build :name => "Jack", :salary => 95000 127 128 callback_log = ["before_adding<new>", "after_adding<new>"] 129 assert_equal callback_log, project.developers_log 130 assert project.save 131 assert_equal 1, project.developers_with_callbacks.count 132 assert_equal callback_log, project.developers_log 133 end 134 101 135 def test_dont_add_if_before_callback_raises_exception 102 136 assert !@david.unchangable_posts.include?(@authorless) trunk/activerecord/test/fixtures/author.rb
r7325 r7935 34 34 :after_remove => :log_after_removing 35 35 has_many :posts_with_proc_callbacks, :class_name => "Post", 36 :before_add => Proc.new {|o, r| o.post_log << "before_adding#{r.id }"},37 :after_add => Proc.new {|o, r| o.post_log << "after_adding#{r.id }"},36 :before_add => Proc.new {|o, r| o.post_log << "before_adding#{r.id || '<new>'}"}, 37 :after_add => Proc.new {|o, r| o.post_log << "after_adding#{r.id || '<new>'}"}, 38 38 :before_remove => Proc.new {|o, r| o.post_log << "before_removing#{r.id}"}, 39 39 :after_remove => Proc.new {|o, r| o.post_log << "after_removing#{r.id}"} 40 40 has_many :posts_with_multiple_callbacks, :class_name => "Post", 41 :before_add => [:log_before_adding, Proc.new {|o, r| o.post_log << "before_adding_proc#{r.id }"}],42 :after_add => [:log_after_adding, Proc.new {|o, r| o.post_log << "after_adding_proc#{r.id }"}]41 :before_add => [:log_before_adding, Proc.new {|o, r| o.post_log << "before_adding_proc#{r.id || '<new>'}"}], 42 :after_add => [:log_after_adding, Proc.new {|o, r| o.post_log << "after_adding_proc#{r.id || '<new>'}"}] 43 43 has_many :unchangable_posts, :class_name => "Post", :before_add => :raise_exception, :after_add => :log_after_adding 44 44 … … 75 75 private 76 76 def log_before_adding(object) 77 @post_log << "before_adding#{object.id }"77 @post_log << "before_adding#{object.id || '<new>'}" 78 78 end 79 79 trunk/activerecord/test/fixtures/project.rb
r4893 r7935 8 8 has_and_belongs_to_many :developers_with_finder_sql, :class_name => "Developer", :finder_sql => 'SELECT t.*, j.* FROM developers_projects j, developers t WHERE t.id = j.developer_id AND j.project_id = #{id}' 9 9 has_and_belongs_to_many :developers_by_sql, :class_name => "Developer", :delete_sql => "DELETE FROM developers_projects WHERE project_id = \#{id} AND developer_id = \#{record.id}" 10 has_and_belongs_to_many :developers_with_callbacks, :class_name => "Developer", :before_add => Proc.new {|o, r| o.developers_log << "before_adding#{r.id }"},11 :after_add => Proc.new {|o, r| o.developers_log << "after_adding#{r.id }"},10 has_and_belongs_to_many :developers_with_callbacks, :class_name => "Developer", :before_add => Proc.new {|o, r| o.developers_log << "before_adding#{r.id || '<new>'}"}, 11 :after_add => Proc.new {|o, r| o.developers_log << "after_adding#{r.id || '<new>'}"}, 12 12 :before_remove => Proc.new {|o, r| o.developers_log << "before_removing#{r.id}"}, 13 13 :after_remove => Proc.new {|o, r| o.developers_log << "after_removing#{r.id}"}