I have two tables with a many to many relationship that I am using has_and_belongs_to_many to define the association.
我有两个表与多对多的关系,我使用has_and_belongs_to_many来定义关联。
class Foo < ActiveRecord::Base
...
has_and_belongs_to_many :bar
...
end
class Bar < ActiveRecord::Base
...
has_and_belongs_to_many :foo
...
end
I also have the class defined to represent the join table
我还定义了表示连接表的类
class BarFoo < ActiveRecord::Base
...
belongs_to :foo
belongs_to :bar
...
end
When I run rake db:seed I get the following error:
当我运行rake db:seed时出现以下错误:
Primary key is not allowed in a has_and_belongs_to_many join table (bar_foo)
If I edit the database and remove the primary key field (ID) from the bar_foo table and then rerun rake db:seed everything works as desired.
如果我编辑数据库并从bar_foo表中删除主键字段(ID),然后重新运行rake db:seed,则所有内容都可以正常工作。
Given the above, what is the preferred means of creating join tables in rails with no primary key?
鉴于上述情况,在没有主键的rails中创建连接表的首选方法是什么?
I also tried using "has_many :bars, :through => :foo" and vise versa but got an error message something like "undefined method 'klass' for nil:NilClass".
我也尝试使用“has_many:bars,:through =>:foo”,反之亦然,但得到的错误信息类似于“未定义的方法'klass'为nil:NilClass”。
3 个解决方案
#1
23
Yes, primary key is not allowed for has_and_belongs_to_many
.
是的,has_and_belongs_to_many不允许使用主键。
You have 2 ways to solve this:
您有两种方法可以解决这个问题:
Remove the primary key on that table. In your migration class:
删除该表上的主键。在您的迁移类中:
create_table :bar_foo, :id => false do |t|
t.integer :bar_id
t.integer :foo_id
end
Apart from this, you will have to delete the file bar_foo.rb
from app/models
and also remove any fixture and test files that might have been generated. A good idea is to call the script/destroy
(or rails destroy
) to destroy the files and then regenerating the migration.
除此之外,您还必须从app / models中删除文件bar_foo.rb,并删除可能已生成的任何fixture和测试文件。一个好主意是调用脚本/ destroy(或rails destroy)来销毁文件然后重新生成迁移。
Or convert to has_many :through
或者转换为has_many:through
class Foo < ActiveRecord::Base
...
has_many :bar_foos
has_many :bars, :through => :bar_foos
...
end
class Bar < ActiveRecord::Base
...
has_many :bar_foos
has_many :foos, :through => :bar_foos
...
end
class BarFoo < ActiveRecord::Base
...
belongs_to :foo
belongs_to :bar
...
end
#2
4
If you want to use a HABTM association you shouldn't create a model for it - just a table bars_foos
with bar_id
and foo_id
integer columns.
如果你想使用HABTM关联,你不应该为它创建一个模型 - 只是一个带有bar_id和foo_id整数列的表bars_foos。
If you need the model in between (e.g. if you want to keep track of created_at
or some other attributes of the relation) you can add additional model e.g. Barred
and then you'd have:
如果您需要介于两者之间的模型(例如,如果您想跟踪created_at或关系的某些其他属性),您可以添加其他模型,例如禁止然后你有:
class Foo < ActiveRecord::Base
...
has_many :bars, :through => :barred
...
end
class Bar < ActiveRecord::Base
...
has_many :foos, :through => :barred
...
end
class Barred < ActiveRecord::Base
has_many :bars
has_many :foos
end
#3
3
You don't need the model
你不需要这个模型
class BarFoo < ActiveRecord::Base
...
belongs_to :foo
belongs_to :bar
...
end
the has_and_belongs_to_many
association will search for a table called bar_foo
in your database what you need to do is generate a migration to create this table.
has_and_belongs_to_many关联将在数据库中搜索名为bar_foo的表,您需要做的是生成迁移以创建此表。
rails generate migration add_table_bar_foo_for_association
rails生成迁移add_table_bar_foo_for_association
then you edit your migration and it should look like this
然后你编辑你的迁移,它应该是这样的
class AddTableBarFooForAssociation < ActiveRecord::Migration
def up
create_table :bar_foo, :id => false do |t|
t.references :bar
t.references :foo
end
end
def down
drop_table :bar_foo
end
end
Now your association should work and also if you need the association to have extra attributes on the join you can use the has_many :through
way and create a model associated to this.
现在您的关联应该起作用,如果您需要关联在连接上有额外的属性,您可以使用has_many:through方式并创建与此关联的模型。
#1
23
Yes, primary key is not allowed for has_and_belongs_to_many
.
是的,has_and_belongs_to_many不允许使用主键。
You have 2 ways to solve this:
您有两种方法可以解决这个问题:
Remove the primary key on that table. In your migration class:
删除该表上的主键。在您的迁移类中:
create_table :bar_foo, :id => false do |t|
t.integer :bar_id
t.integer :foo_id
end
Apart from this, you will have to delete the file bar_foo.rb
from app/models
and also remove any fixture and test files that might have been generated. A good idea is to call the script/destroy
(or rails destroy
) to destroy the files and then regenerating the migration.
除此之外,您还必须从app / models中删除文件bar_foo.rb,并删除可能已生成的任何fixture和测试文件。一个好主意是调用脚本/ destroy(或rails destroy)来销毁文件然后重新生成迁移。
Or convert to has_many :through
或者转换为has_many:through
class Foo < ActiveRecord::Base
...
has_many :bar_foos
has_many :bars, :through => :bar_foos
...
end
class Bar < ActiveRecord::Base
...
has_many :bar_foos
has_many :foos, :through => :bar_foos
...
end
class BarFoo < ActiveRecord::Base
...
belongs_to :foo
belongs_to :bar
...
end
#2
4
If you want to use a HABTM association you shouldn't create a model for it - just a table bars_foos
with bar_id
and foo_id
integer columns.
如果你想使用HABTM关联,你不应该为它创建一个模型 - 只是一个带有bar_id和foo_id整数列的表bars_foos。
If you need the model in between (e.g. if you want to keep track of created_at
or some other attributes of the relation) you can add additional model e.g. Barred
and then you'd have:
如果您需要介于两者之间的模型(例如,如果您想跟踪created_at或关系的某些其他属性),您可以添加其他模型,例如禁止然后你有:
class Foo < ActiveRecord::Base
...
has_many :bars, :through => :barred
...
end
class Bar < ActiveRecord::Base
...
has_many :foos, :through => :barred
...
end
class Barred < ActiveRecord::Base
has_many :bars
has_many :foos
end
#3
3
You don't need the model
你不需要这个模型
class BarFoo < ActiveRecord::Base
...
belongs_to :foo
belongs_to :bar
...
end
the has_and_belongs_to_many
association will search for a table called bar_foo
in your database what you need to do is generate a migration to create this table.
has_and_belongs_to_many关联将在数据库中搜索名为bar_foo的表,您需要做的是生成迁移以创建此表。
rails generate migration add_table_bar_foo_for_association
rails生成迁移add_table_bar_foo_for_association
then you edit your migration and it should look like this
然后你编辑你的迁移,它应该是这样的
class AddTableBarFooForAssociation < ActiveRecord::Migration
def up
create_table :bar_foo, :id => false do |t|
t.references :bar
t.references :foo
end
end
def down
drop_table :bar_foo
end
end
Now your association should work and also if you need the association to have extra attributes on the join you can use the has_many :through
way and create a model associated to this.
现在您的关联应该起作用,如果您需要关联在连接上有额外的属性,您可以使用has_many:through方式并创建与此关联的模型。