After creating classes Foo and Bar and connecting them
together with has_and_belongs_to_many, I attempted to
add an association between them with bar.foos << foo.
I was surprised to see two connector rows show up in
the bars_foos table. However, only one connector row
showed up when I added the association with foo.bars
<< bar.
On further inspection, I found that the Foo class
definition was being executed twice. The first
execution was an explicit require ''foo'' statement.
The second execution seems strange to me: even without
the require, the code was going out and looking for a
foo.rb.
In other words, the duplicate join rows were caused by
executing something like this:
class Foo
has_and_belongs_to_many :bars
end
class Foo
has_and_belongs_to_many :bars
end
So I now know how to fix my problem, but I still have
a few questions for all you rails users:
1) Why does Ruby look for a foo.rb when I mention Foo
in a statement?
2) Can I prevent this, so I can have better control of
how many times class definitions get executed?
3) Can I surround my class definitions with code that
prevents them from being executed twice?
4) Shouldn''t active_record ignore the second
has_and_belongs_to_many instead of calling a second
insert on save?
5) Why does the workaround (adding bars to a foo
instead of foos to a bar) work?
Thanks in advance for your thoughts, --DTS
_____________________test.rb___________
#!/usr/bin/ruby
require ''rubygems''
require_gem ''activerecord''
require ''bar''
require ''foo''
$*.length == 3 or raise %Q(
Usage:
"./test.rb [db username] [db password] bar" to see
duplicate rows
"./test.rb [db username] [db password] foo" to see the
workaround
)
ActiveRecord::Base.establish_connection(
:adapter => "mysql",
:host => "localhost",
:username => $*[0],
:password => $*[1],
:database => "db"
)
Foo.destroy_all
Bar.destroy_all
foo = Foo.new(''code'' => ''foo1'')
foo.save
bar = Bar.new(''code'' => ''bar1'')
foos = Foo.find_by_code(''foo1'')
case $*[2]
when ''bar'': bar.foos << foo
when ''foo'': foo.bars << bar
end
bar.save
puts "bar.foos.size: %d" % bar.foos.size
puts "foo.bars.size: %d" % foo.bars.size
________________bar.rb____________
#!/usr/bin/ruby
require ''rubygems''
require_gem ''activerecord''
#require ''foo''
class Bar < ActiveRecord::Base
has_and_belongs_to_many :foos
puts "Bar defined"
end
______________foo.rb_____________
#!/usr/bin/ruby
require ''rubygems''
require_gem ''activerecord''
#require ''bar''
class Foo < ActiveRecord::Base
has_and_belongs_to_many :bars
puts "Foo defined"
end
_______________db.sql____________
drop database db;
create database db;
use db;
drop table if exists foos;
create table foos (
id int(11) not null
auto_increment,
code varchar(40) not null,
primary key(id)
);
drop table if exists bars;
create table bars (
id int(11) not null
auto_increment,
code varchar(40) not null,
primary key(id)
);
drop table if exists bars_foos;
create table bars_foos (
bar_id int(11) not null,
foo_id int(11) not null
);
__________________________________
Do you Yahoo!?
Yahoo! Personals - Better first dates. More second dates.
http://personals.yahoo.com