使用的是rails2.0.2版本,。现有表结构如下:
create table mc$dr_role(
id number primary key,
role varchar2(30),
enabled varchar2(10)
)
create table mc$dr_user_roles(
id number primary key,
user_id number ,
role_id number
)
create table users(
id number primary key,
name varchar2(30) ,
passwd varchar2(30)
)
在model中写法是:
class Role < ActiveRecord::Base
set_table_name "mc$dr_role"
has_many :user_roles, :class_name =>"DrUserRole", :foreign_key=>"id",
:dependent=> :delete_all
has_many :users, :through => :user_roles
end
class User < ActiveRecord::Base
has_many :user_roles, :class_name =>"DrUserRole", :foreign_key=>"id",
:dependent=> :destroy
has_many :roles, :through => :user_roles
end
class DrUserRole < ActiveRecord::Base
set_table_name "mc$dr_user_roles"
belongs_to :user, :class_name =>"User", :foreign_key=>"user_id"
belongs_to :role, :class_name =>"Role", :foreign_key=>"role_id"
end
在执行@user.roles << role 报错Cannot associate new records through 'User#user_roles' on '#'. Both records must have an id in order to create the has_many :through record associating them.
我很奇怪关联中“#”是哪里出来的?没弄明白。foreign_key这个配置选项我都已经尝试过好几次变化了,都没成功。。。不知道原因在那里?还是对于这样自定义的表进行关联式有问题的?
正常来说
按照你所需要的建多对多关联表 是这样弄的
ruby generate model role role:string enable:string
ruby generate model user name:string pass:string
ruby generate model UserRole user_id:integer role_id:integer
rake db:migrate
就生成对应的表和字段了
然后是model
class Role < ActiveRecord::Base
has_many :user_roles,:dependent=> :destroy
has_many :users, :through => :user_roles
end
class User < ActiveRecord::Base
has_many :user_roles,:dependent=> :destroy
has_many :roles, :through => :user_roles
end
class DrUserRole < ActiveRecord::Base
belongs_to :user
belongs_to :role
end
over
你的错误应该是指定了错误的外键 导致的..
对于belongs_to :foreign_key是默认的,除非你的,主键不是id,如果你只是修改了table没有改field名的话,考虑去掉:foreign_key。
参考官方API
引用
:foreign_key
Specify the foreign key used for the association. By default this is guessed to be the name of the association with an "_id" suffix. So a class that defines a belongs_to :person association will use "person_id" as the default :foreign_key. Similarly, belongs_to :favorite_person, :class_name => "Person" will use a foreign key of "favorite_person_id".
那么,楼主的问题在哪呢?
楼主最主要不一样的地方是,打破了一个默认规则,就是不希望,物理表名和Model名一致。
实际,对于这样的需要只需要set_table就够了,也就是model写成这样
class Role < ActiveRecord::Base
set_table_name "mc$dr_role"
has_many :dr_user_roles,
:dependent=> :delete_all
has_many :users, :through => :dr_user_roles
end
class User < ActiveRecord::Base
has_many :dr_user_roles,
:dependent=> :destroy
has_many :roles, :through => :dr_user_roles
end
class DrUserRole < ActiveRecord::Base
set_table_name "mc$dr_user_roles"
belongs_to :user
belongs_to :role
end
那么,最开始说了,什么时候用指定:foreign_key
接着看看,什么时候用:class_name,这个应该是,只有定义的关系和类名不一致的时候。例如:假设楼主,很坚持使用user_roles,就可以按下面写
Ruby代码
class Role < ActiveRecord::Base
set_table_name "mc$dr_role"
has_many :user_roles,
:class_name =>"DrUserRole",
:dependent=> :delete_all
has_many :users, :through => :user_roles
end
class User < ActiveRecord::Base
has_many :user_roles,
:class_name =>"DrUserRole",
:dependent=> :destroy
has_many :roles, :through => :user_roles
end
class DrUserRole < ActiveRecord::Base
set_table_name "mc$dr_user_roles"
belongs_to :user
belongs_to :role
end
换句话说,这里没有问题,没有不一致的问题。
只是,不应该指定一个,不太合逻辑的foreign_key。也就是说belongs_to的class_name和forein_key可以不去掉,顶多就是重复写了一遍。has_many的foreign_key也可以去掉,因为和默认的外键是一样的,毕竟你的id还是主键。
那么,如果楼主说了,我就偏要写呢,
嗯,也可以,那就像楼上说的,那得把foreign_key写对。
has_many的默认foreign_key是什么呢,那就要看看逻辑啦
你有很多子表,那么外键就是你的主键了,所以应该是,主表名加主id。
或者,也可以参考,官方API
:foreign_key
# Specify the foreign key used for the association. By default this is guessed to be the name of this class in lower-case and "_id" suffixed. So a Person class that makes a has_many association will use "person_id" as the default :foreign_key.
也就是说,楼主的Model写成下面的,也没问题。
class Role < ActiveRecord::Base
set_table_name "mc$dr_role"
has_many :user_roles, :class_name =>"DrUserRole", :foreign_key=>"role_id",
:dependent=> :delete_all
has_many :users, :through => :user_roles
end
class User < ActiveRecord::Base
has_many :user_roles, :class_name =>"DrUserRole", :foreign_key=>"user_id",
:dependent=> :destroy
has_many :roles, :through => :user_roles
end
class DrUserRole < ActiveRecord::Base
set_table_name "mc$dr_user_roles"
belongs_to :user, :class_name =>"User", :foreign_key=>"user_id"
belongs_to :role, :class_name =>"Role", :foreign_key=>"role_id"
end
最后,说说,为什么:foreign_key写成id的问题,@user.roles能找到,但添加会有问题呢?
因为,:foreign_key写成id,@user.roles就变成
DrUserRole.find_by_id(@user.id)
而不是,正确的
DrUserRole.find_by_user_id(@user.id)