ruby-on-rails - accept_nested_attributes_for 与 Rails 中的关系数据库逻辑相矛盾
问题描述
Ruby on Rails 模型逻辑与关系数据库逻辑冲突。
在 Ruby on Rails 中,拥有 , 的模型belongs_to
将在数据库中拥有外键。所以,模型:
class Student < ApplicationRecord
belongs_to :university
end
class University < ApplicationRecord
has_many :university
end
将有迁移文件:
class CreateStudents < ActiveRecord::Migration[6.0]
t.string :name
t.references :university, foreign_key: true
end
class CreateUniversities < ActiveRecord::Migration[6.0]
t.string :name
end
而且,从逻辑上讲,学生将在数据库中拥有 University foreign_key,如下所示:
Student
-id int (PK)
-name varchar
-University_id int (FK)
University
-id int (PK)
-name varchar
到目前为止这么好
当我想accepts_nested_attributes_for
在学生模型中引用_form.html.erb
. 为了使用它,宿主模型(在本例中为 Student)必须具有用于引用表的 ahas_one
而不是 a 。belongs_to
所以它会变成:
class Student < ApplicationRecord
has_one :university
accepts_nested_attributes_for :university
end
请注意,为了accepts_nested_attributes_for
用于引用大学,学生模型必须将其替换belongs_to :university
为 a has_one :university
,而大学将有 a belongs_to :student
,而不是 a has_many :student
。
因此,在迁移文件中,Student 将失去对 University 的引用,而后者将引用 Student,如下所示:
class CreateStudents < ActiveRecord::Migration[6.0]
t.string :name
end
class CreateUniversities < ActiveRecord::Migration[6.0]
t.string :name
t.references :student, foreign_key: true
end
并且数据库将强制为:
Student
-id int (PK)
-name varchar
University
-id int (PK)
-name varchar
-Student_id int (FK)
这是错误的,因为大学与学生之间应该存在一对多的关系,而不是相反。
那么,有没有一种方法可以使用accepts_nested_attributes_for
,而不必通过强制反转模型中的关系来搞乱关系数据库逻辑?
解决方案
accepts_nested_attributes_for
嵌套属性允许您通过父项将属性保存在关联记录上。
因此,您可能对您想成为哪个父母略有混淆。如果您使学生成为具有大学嵌套属性的父级,则您不会引用大学,而是实质上创建新的大学记录或使用您在学生表单中使用的嵌套属性更新现有记录。
One-to-one
Consider a Member model that has one Avatar:
class Member < ActiveRecord::Base
has_one :avatar
accepts_nested_attributes_for :avatar
end
Enabling nested attributes on a one-to-one association allows you to create the member and avatar in one go:
params = { member: { name: 'Jack', avatar_attributes: { icon: 'smiling' } } }
member = Member.create(params[:member])
member.avatar.id # => 2
member.avatar.icon # => 'smiling'
因此,您只会为使用这些嵌套属性的每个学生更新/创建新的大学记录。
这是一对多:
One-to-many
Consider a member that has a number of posts:
class Member < ActiveRecord::Base
has_many :posts
accepts_nested_attributes_for :posts
end
You can now set or update attributes on the associated posts through an attribute hash for a member: include the key :posts_attributes with an array of hashes of post attributes as a value.
For each hash that does not have an id key a new record will be instantiated, unless the hash also contains a _destroy key that evaluates to true.
params = { member: {
name: 'joe', posts_attributes: [
{ title: 'Kari, the awesome Ruby documentation browser!' },
{ title: 'The egalitarian assumption of the modern citizen' },
{ title: '', _destroy: '1' } # this will be ignored
]
}}
member = Member.create(params[:member])
member.posts.length # => 2
member.posts.first.title # => 'Kari, the awesome Ruby documentation browser!'
member.posts.second.title # => 'The egalitarian assumption of the modern citizen'
您还可以在上面的一对多示例中看到这一点。您是否希望在发布学生记录时更改/创建大学记录?
如果您只是在寻找参考资料,那么您在第一个示例中基本上已经有了它,并且可以稍微改变您的路线以让学生被大学参考。
然后,一旦嵌套了路由,您就可以对表单部分做一些工作。这是一个正在这样做的人
因此,也许如果我离开这里,请描述为什么在创建/更新学生时要创建/更新大学。如果那是你想要做的。
这将有助于其他人了解您的上下文,并可能帮助其他人了解您使用嵌套属性的意图。
例如,添加您的部分表单并解释您的目标。
编辑: 作为一个平底船,你也许可以看看有并且属于许多协会。 本教程讨论具有多对多关联的嵌套属性。但是,由于我不确定您在它之后可能会或可能不会有帮助。
另一个平底船听起来像是您希望在更新学生的大学记录时更改它们。所以你会有学生属于大学和大学有很多学生但也有很多大学记录并且学生有很多/有一个大学记录和记录属于两者。又名: 这个
然后你可以让学生接受大学记录的嵌套属性。
推荐阅读
- groovy - Groovyc:unexpected token: assert -- 为什么?(常规 2.5.6)
- reactjs - 禁用水合/仅部分水合 Next.js 应用程序
- email - AMP 未显示在 Gmail 中
- javascript - 如果正则表达式在使用 jQuery 的handsontable 中无效,则禁用按钮
- android - 从另一个活动访问在一个活动中创建的数据库
- oracle - 如何将 Octave 连接到 Oracle 数据库?
- javascript - 可滚动视图/组件中按钮的固定位置
- dart - 如何使用颤振将 web3 连接到以太坊网络?
- html - flex-grow 上的 flexbox 全高但超过视口高度
- scala - Scala:返回依赖类型