Skip to content
This repository
Browse code

Fix the has_and_belongs_to_many #create doesn't populate the join for…

… new records. Closes #3692 [josh@hasmanythrough.com]

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@4379 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
commit 06075a9eb5ddf255ed561bc4cdddef214d7c63aa 1 parent 8498c74
risk danger olson authored May 29, 2006
2  activerecord/CHANGELOG
... ...
@@ -1,5 +1,7 @@
1 1
 *SVN*
2 2
 
  3
+* Fix the has_and_belongs_to_many #create doesn't populate the join for new records.  Closes #3692 [josh@hasmanythrough.com]
  4
+
3 5
 * Provide Association Extensions access to the instance that the association is being accessed from.  
4 6
   Closes #4433 [josh@hasmanythrough.com]
5 7
 
6  activerecord/lib/active_record/associations.rb
@@ -763,6 +763,10 @@ def belongs_to(association_id, options = {})
763 763
       # * <tt>collection.size</tt> - returns the number of associated objects.
764 764
       # * <tt>collection.find(id)</tt> - finds an associated object responding to the +id+ and that
765 765
       #   meets the condition that it has to be associated with this object.
  766
+      # * <tt>collection.build(attributes = {})</tt> - returns a new object of the collection type that has been instantiated
  767
+      #   with +attributes+ and linked to this object through the join table but has not yet been saved.
  768
+      # * <tt>collection.create(attributes = {})</tt> - returns a new object of the collection type that has been instantiated
  769
+      #   with +attributes+ and linked to this object through the join table and that has already been saved (if it passed the validation).
766 770
       #
767 771
       # Example: An Developer class declares <tt>has_and_belongs_to_many :projects</tt>, which will add:
768 772
       # * <tt>Developer#projects</tt>
@@ -775,6 +779,8 @@ def belongs_to(association_id, options = {})
775 779
       # * <tt>Developer#projects.empty?</tt>
776 780
       # * <tt>Developer#projects.size</tt>
777 781
       # * <tt>Developer#projects.find(id)</tt>
  782
+      # * <tt>Developer#projects.build</tt> (similar to <tt>Project.new("project_id" => id)</tt>)
  783
+      # * <tt>Developer#projects.create</tt> (similar to <tt>c = Project.new("project_id" => id); c.save; c</tt>)
778 784
       # The declaration may include an options hash to specialize the behavior of the association.
779 785
       # 
780 786
       # Options are:
11  activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb
@@ -13,6 +13,17 @@ def build(attributes = {})
13 13
         record
14 14
       end
15 15
 
  16
+      def create(attributes = {})
  17
+        # Can't use Base.create since the foreign key may be a protected attribute.
  18
+        if attributes.is_a?(Array)
  19
+          attributes.collect { |attr| create(attr) }
  20
+        else
  21
+          record = build(attributes)
  22
+          insert_record(record) unless @owner.new_record?
  23
+          record
  24
+        end
  25
+      end
  26
+
16 27
       def find_first
17 28
         load_target.first
18 29
       end
28  activerecord/test/associations_test.rb
@@ -1354,6 +1354,20 @@ def test_build
1354 1354
     devel.save
1355 1355
     assert !proj.new_record?
1356 1356
     assert_equal devel.projects.last, proj
  1357
+    assert_equal Developer.find(1).projects.last, proj  # prove join table is updated
  1358
+  end
  1359
+  
  1360
+  def test_build_by_new_record
  1361
+    devel = Developer.new(:name => "Marcel", :salary => 75000)
  1362
+    proj1 = devel.projects.build(:name => "Make bed")
  1363
+    proj2 = devel.projects.build(:name => "Lie in it")
  1364
+    assert_equal devel.projects.last, proj2
  1365
+    assert proj2.new_record?
  1366
+    devel.save
  1367
+    assert !devel.new_record?
  1368
+    assert !proj2.new_record?
  1369
+    assert_equal devel.projects.last, proj2
  1370
+    assert_equal Developer.find_by_name("Marcel").projects.last, proj2  # prove join table is updated
1357 1371
   end
1358 1372
   
1359 1373
   def test_create
@@ -1361,6 +1375,20 @@ def test_create
1361 1375
     proj = devel.projects.create("name" => "Projekt")
1362 1376
     assert_equal devel.projects.last, proj
1363 1377
     assert !proj.new_record?
  1378
+    assert_equal Developer.find(1).projects.last, proj  # prove join table is updated
  1379
+  end
  1380
+  
  1381
+  def test_create_by_new_record
  1382
+    devel = Developer.new(:name => "Marcel", :salary => 75000)
  1383
+    proj1 = devel.projects.create(:name => "Make bed")
  1384
+    proj2 = devel.projects.create(:name => "Lie in it")
  1385
+    assert_equal devel.projects.last, proj2
  1386
+    assert proj2.new_record?
  1387
+    devel.save
  1388
+    assert !devel.new_record?
  1389
+    assert !proj2.new_record?
  1390
+    assert_equal devel.projects.last, proj2
  1391
+    assert_equal Developer.find_by_name("Marcel").projects.last, proj2  # prove join table is updated
1364 1392
   end
1365 1393
   
1366 1394
   def test_uniq_after_the_fact

0 notes on commit 06075a9

Please sign in to comment.
Something went wrong with that request. Please try again.