a little perspective on the behavior of models that share a has_and_belongs_to_many relation

Hi, I am experimenting with rails 2.1 using the Netbeans IDE. Recently I have been looking at the behavior of rails when dealing with two models that share a has_and_belongs_to_many relation.

I created two simple models, 'Foo' and 'Bar' that share a has_and_belongs_to_many relation. (both foo and bar have a name:string and a value:int field and contain records like: 'A', 10 'B', 20 'C', 30 etc. ) I also created a table 'foos_bars' (with :id=>false). After generating the scaffolding, I updated views/foos/new.html.erb to include this bit of code:

<% for item in Bar.all %>                 <%= check_box_tag 'foo[bar_ids]', item.id, false %> < %= item.name %><br> <% end %>

This seems to work as advertised. In the 'new' dialog, if I check boxes in the form, and then submit the form, the 'foos_bars' join table is updated with new rows representing the has_and_belongs_to_many relation between foo and bar.

So my next question was: Is rails clever enough to figure out join tables when one of the models in the relationship has camel-cased characters? i.e.: What happens if I have two models 'FooBar' and 'Gizmo' and their corresponding tables that are identical to 'foo' and 'bar' in all but name.

So I went through all of the same steps I did for 'Foo' and 'Bar', except that the models are named 'FooBar' and 'Gizmo'. I created a similar join table, 'foo_bars_gizmos', and I updated views/foo_bar/ new.html.erb with the same bit of code above with the names changed to reflect the different models.

<% for item in Gizmo.all %>                 <%= check_box_tag 'foo[gizmo_ids]', item.id, false %> <%= item.name %><br> <% end %>

So the question is: does the 'new' page for FooBar work the same as the 'new' page for Foo?

The answer, in short, appears to be no.

Both initial 'new' HTML pages appear to be identical, reflecting only the changes to the model names. However in the case of 'new' page for FooBar, when I submit the page, rails skips updating the database and shows the index page.

Here is the segment from the development log for the 'new' page for 'Foo' (which works as expected)

(display the initial 'new' form) Processing FoosController#new (for 127.0.0.1 at 2008-06-26 10:06:06) [GET]   Session ID: BAh7ByIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNo SGFzaHsABjoKQHVzZWR7ADoMY3NyZl9pZCIlMjYyMjgwZmRkMDZmOGQ3YWZk MmY1NGU3ZWNkYzU2MDQ=--42def924372179a1cf95f2229a39d317180974cb   Parameters: {"controller"=>"foos", "action"=>"new"}   Foo Columns (0.008680) SHOW FIELDS FROM `foos`   Bar Load (0.007275) SELECT * FROM `bars` Rendering template within layouts/foos Rendering foos/new   CACHE (0.000000) SELECT * FROM `bars`   Bar Columns (0.008892) SHOW FIELDS FROM `bars` Completed in 0.16275 (6 reqs/sec) | Rendering: 0.08242 (50%) | DB: 0.03339 (20%) | 200 OK [http://localhost/foos/new\]

(process the submission) Processing FoosController#create (for 127.0.0.1 at 2008-06-26 10:06:23) [POST]   Session ID: BAh7ByIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNo SGFzaHsABjoKQHVzZWR7ADoMY3NyZl9pZCIlMjYyMjgwZmRkMDZmOGQ3YWZk MmY1NGU3ZWNkYzU2MDQ=--42def924372179a1cf95f2229a39d317180974cb   Parameters: {"authenticity_token"=>"0e2e28cc2c93625db6925872dfc05190bbc72ac9", "foo"=>{"name"=>"L", "value"=>"75", "bar_ids"=>["3", "4"]}, "commit"=>"Create", "controller"=>"foos", "action"=>"create"}   Foo Columns (0.006579) SHOW FIELDS FROM `foos`   Bar Columns (0.006674) SHOW FIELDS FROM `bars`   Bar Load (0.004120) SELECT * FROM `bars` WHERE (`bars`.`id` IN (3,4))   SQL (0.000788) BEGIN   SQL (0.000732) COMMIT   SQL (0.000975) BEGIN   Foo Create (0.000872) INSERT INTO `foos` (`name`, `value`, `created_at`, `updated_at`) VALUES('L', 75, '2008-06-26 17:06:23', '2008-06-26 17:06:23')   bars_foos Columns (0.006560) SHOW FIELDS FROM `bars_foos`   SQL (0.001076) INSERT INTO `bars_foos` (`foo_id`, `bar_id`) VALUES (9, 3)   bars_foos Columns (0.005846) SHOW FIELDS FROM `bars_foos`   SQL (0.001320) INSERT INTO `bars_foos` (`foo_id`, `bar_id`) VALUES (9, 4)   SQL (0.003362) COMMIT Redirected to http://localhost:3000/foos/9 Completed in 0.17016 (5 reqs/sec) | DB: 0.03890 (22%) | 302 Found [http://localhost/foos\]

(Looks OK, right?)

Here is the segment from the development log for the 'new' page for 'FooBar'

(display the initial 'new' form) Processing FooBarsController#new (for 127.0.0.1 at 2008-06-26 10:38:56) [GET]   Session ID: BAh7ByIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNo SGFzaHsGOgtub3RpY2UiIkZvbyB3YXMgc3VjY2Vzc2Z1bGx5IGNyZWF0ZWQu BjoKQHVzZWR7BjsGVDoMY3NyZl9pZCIlMjYyMjgwZmRkMDZmOGQ3YWZkMmY1 NGU3ZWNkYzU2MDQ=--f26c74fc0800da5ae785e40561fbbe88d2357ee3   Parameters: {"controller"=>"foo_bars", "action"=>"new"}   FooBar Columns (0.008397) SHOW FIELDS FROM `foo_bars`   Gizmo Load (0.006131) SELECT * FROM `gizmos` Rendering template within layouts/foo_bars Rendering foo_bars/new   Gizmo Columns (0.006696) SHOW FIELDS FROM `gizmos` Completed in 0.13910 (7 reqs/sec) | Rendering: 0.06515 (46%) | DB: 0.02122 (15%) | 200 OK [http://localhost/foo_bars/new\]

(process the submission) Processing FooBarsController#index (for 127.0.0.1 at 2008-06-26 10:39:14) [POST]   Session ID: BAh7ByIKZmxhc2hJQzonQWN0aW9uQ29udHJvbGxlcjo6Rmxhc2g6OkZsYXNo SGFzaHsABjoKQHVzZWR7ADoMY3NyZl9pZCIlMjYyMjgwZmRkMDZmOGQ3YWZk MmY1NGU3ZWNkYzU2MDQ=--42def924372179a1cf95f2229a39d317180974cb   Parameters: {"authenticity_token"=>"0e2e28cc2c93625db6925872dfc05190bbc72ac9", "foo_bar"=>{"name"=>"M", "value"=>"80", "gizmo_ids"=>["1", "2"]}, "commit"=>"Create", "controller"=>"foo_bars", "action"=>"index"}   FooBar Load (0.006378) SELECT * FROM `foo_bars` Rendering template within layouts/foo_bars Rendering foo_bars/index   FooBar Columns (0.006780) SHOW FIELDS FROM `foo_bars` Completed in 0.11590 (8 reqs/sec) | Rendering: 0.06975 (60%) | DB: 0.01316 (11%) | 200 OK [http://localhost/foo_bars\]

Note, in this last segment, rails has somehow changed the action from 'create' to 'index'.

My questions are: How? and Why?