`

Rails ActiveRecorde has_many foreign_key 使用

阅读更多
使用的是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)
分享到:
评论
1 楼 lfx_cool 2009-07-10  
粗看了下,不太明白,待仔细研究。。

相关推荐

    rails_apps_composer, 一个 gem,为 Rails 启动应用程序创建 Rails 应用程序模板.zip

    rails_apps_composer, 一个 gem,为 Rails 启动应用程序创建 Rails 应用程序模板 Rails 应用编辑器 Rails 应用程序编辑器 gem 安装一个 命令行 工具来从"食谱"的..."你可以使用 rails_apps_composer gem 执行以下操作:

    rails_semantic_logger, Rails 语义记录器用语义记录器替换 Rails 缺省记录器.zip

    rails_semantic_logger, Rails 语义记录器用语义记录器替换 Rails 缺省记录器 Rails 语义记录器 语义记录器用语义记录器替代 Rails 缺省记录器。http://github.com/rocketjob/rails_semantic_logger文档有关完整文档...

    inspinia admin - v2.5 Rails_Full_Version

    "inspinia admin - v2.5 Rails_Full_Version" 是一个基于Rails框架构建的后台管理系统的完整版本。这个系统采用流行的Inspinia Admin模板,提供了丰富的功能和自定义选项,旨在帮助开发者快速构建高效、现代且用户...

    InspiniaAdmin 2.6.1 Rails_Full_Version

    在Rails_Full_Version压缩包中,包含了完整的源代码和必要的资源文件,开发者可以通过解压并导入到Rails项目中,按照官方文档进行配置和定制。同时,这个版本可能还包含了升级记录、更改日志和可能的bug修复,以保证...

    agile_web_development_with_rails_3rd_edition.9994652073.pdf

    书中强调了版本控制的重要性,特别是在使用Rails这样的活跃开源项目时。由于Rails不断更新,新功能的引入或API的修改都可能导致代码兼容性问题。为了确保代码的正确运行,作者建议在使用本书示例代码之前,先检查...

    rails_best_practices:Rails项目的代码度量工具

    rails_best_practices rails_best_practices是用于检查Rails代码质量的代码度量工具。 它支持以下ORM / ODM: 活动记录 蒙古型 mongomapper 以及以下模板引擎: erb 哈姆 减肥 拉布尔 rails_best_practices...

    RestFul_Rails_Dev_pdf_v_0.1.zip

    本资料“RestFul_Rails_Dev_pdf_v_0.1.zip”包含了《RESTful Rails Development》的翻译版,将深入探讨如何在Rails中实现RESTful的设计模式。 首先,RESTful设计的核心概念是资源(Resources)。在Rails中,资源...

    inspinia admin - v2.5 Rails_Seed_Project

    本文将详细探讨其在Rails框架下的种子项目(Rails_Seed_Project),旨在帮助开发者更好地理解和运用这一强大的工具。 首先,我们来了解一下“Inspinia Admin”。这是一款基于Bootstrap 3构建的响应式后台模板,提供...

    InspiniaAdmin 2.5 Rails_Seed_Project

    InspiniaAdmin 2.5 Rails_Seed_Project是一款基于Bootstrap框架的高级管理模板,专为Ruby on Rails开发者设计,旨在加速Web应用程序的开发过程。这个项目作为种子启动器,提供了完整的后台管理界面,包括丰富的UI...

    Rails_3_Cheat_Sheets.pdf

    Rails_3_Cheat_Sheets.pdf

    many-to-many-through:这是使用has_many的许多示例教程

    这是关于如何使用has_many :throght创建多对多关联的完整示例has_many :throght在此示例中,我使用staff模型和client模型,其中人员有很多客户,而客户有很多员工 操作说明 在下面的终端中输入 $ rails new many - ...

    trades:Ruby on Rails-has_many_through高级关联

    自述文件 该自述文件通常会记录启动和运行应用程序所需的所有步骤。 您可能要讲的内容: Ruby版本 系统依赖 配置 数据库创建 数据库初始化 如何运行测试套件 服务(作业队列,缓存服务器,搜索引擎等) ...

    rails_admin_acts_as_list:rails_admin插件以对记录进行排序

    介绍插件,用于对记录进行排序(使用 gem)安装要启用rails_admin_acts_as_list,请将以下内容添加到您的Gemfile : gem 'rails_admin_acts_as_list'gem 'rails_admin' 重要提示: rails_admin_acts_as_list之前必须...

    InspiniaAdmin 2.5 Rails_full_version

    InspiniaAdmin 2.5 Rails_full_version

    Complex Rails system_Rails_优化_

    3. **数据缓存**:使用低级缓存`Rails.cache`存储查询结果,避免重复计算。 三、代码优化 1. **避免在循环中进行数据库查询**:将查询移到循环之外,减少不必要的数据库交互。 2. **减少视图复杂性**:保持视图...

    inspinia_admin_v2.5_Rails_Full_Version

    该模板包含的文件列表“inspinia_admin_v2.5_Rails_Full_Version”很可能包括以下组成部分: 1. **静态资源**:CSS样式文件、JavaScript脚本和图像资源。这些文件用于构建用户界面,包括响应式布局、图表、表单元素...

    rails_email_preview, 在 Rails 中,预览和编辑应用程序邮件程序模板.zip

    rails_email_preview, 在 Rails 中,预览和编辑应用程序邮件程序模板 Rails 电子邮件预览 使用这里 Rails 引擎在浏览器中预览电子邮件。 兼容 Rails 4.2 。电子邮件审阅: 所有电子邮件预览的列表: 代表有两个主题...

    rails_admin_content_builder:使用rails_admin创建内容的简单方法

    gem 'rails_admin_content_builder' 运行生成器并进行迁移 rails g rails_admin_content_builder rake db:migrate 在app / assets / application.scss中添加样式 * = require rails_admin_content_builder 用法 ...

Global site tag (gtag.js) - Google Analytics