asi*_*ibs 2 ruby activerecord ruby-on-rails ruby-on-rails-5
使用 Rails 5:
gem 'rails', '~> 5.0.0', '>= 5.0.0.1'
Run Code Online (Sandbox Code Playgroud)
我已经创建了我能想到的最简单的例子来演示这个问题:
父母.rb
class Parent < ApplicationRecord
has_many :children
accepts_nested_attributes_for :children
end
Run Code Online (Sandbox Code Playgroud)
孩子.rb
class Child < ApplicationRecord
belongs_to :parent
end
Run Code Online (Sandbox Code Playgroud)
创建父项,保存,创建子项,保存(有效)
使用rails console,创建一个新的父级,然后保存,然后从父级构建一个子级,然后保存父级,工作正常:
irb(main):004:0> parent = Parent.new
=> #<Parent id: nil, created_at: nil, updated_at: nil>
irb(main):005:0> parent.save
(0.5ms) BEGIN
SQL (0.4ms) INSERT INTO `parents` (`created_at`, `updated_at`) VALUES ('2016-09-25 13:05:44', '2016-09-25 13:05:44')
(3.2ms) COMMIT
=> true
irb(main):006:0> parent.children.build
=> #<Child id: nil, parent_id: 1, created_at: nil, updated_at: nil>
irb(main):007:0> parent.save
(0.5ms) BEGIN
Parent Load (0.5ms) SELECT `parents`.* FROM `parents` WHERE `parents`.`id` = 1 LIMIT 1
SQL (0.7ms) INSERT INTO `children` (`parent_id`, `created_at`, `updated_at`) VALUES (1, '2016-09-25 13:05:52', '2016-09-25 13:05:52')
(1.3ms) COMMIT
=> true
Run Code Online (Sandbox Code Playgroud)
创建父项,创建子项,保存(不起作用)
但是,如果我尝试创建一个新的父级,然后在不保存父级的情况下构建子级,最后在最后保存父级,则事务将失败并回滚:
irb(main):008:0> parent = Parent.new
=> #<Parent id: nil, created_at: nil, updated_at: nil>
irb(main):009:0> parent.children.build
=> #<Child id: nil, parent_id: nil, created_at: nil, updated_at: nil>
irb(main):010:0> parent.save
(0.5ms) BEGIN
(0.4ms) ROLLBACK
=> false
Run Code Online (Sandbox Code Playgroud)
谁能解释为什么,以及如何解决?
更新
创建父级和子级,然后如果通过,则保存确实有效validate: false,因此这表明子级验证失败的问题,因为它需要设置 parent_id - 但大概子级验证必须在父级保存之前运行然后,或者它不会失败?
irb(main):001:0> parent = Parent.new
=> #<Parent id: nil, created_at: nil, updated_at: nil>
irb(main):002:0> parent.children.build
=> #<Child id: nil, parent_id: nil, created_at: nil, updated_at: nil>
irb(main):003:0> parent.save(validate: false)
(0.7ms) BEGIN
SQL (0.9ms) INSERT INTO `parents` (`created_at`, `updated_at`) VALUES ('2016-09-25 15:02:20', '2016-09-25 15:02:20')
SQL (0.8ms) INSERT INTO `children` (`parent_id`, `created_at`, `updated_at`) VALUES (3, '2016-09-25 15:02:20', '2016-09-25 15:02:20')
(1.6ms) COMMIT
=> true
Run Code Online (Sandbox Code Playgroud)
更新 2
如果我从 中删除该行,它也可以使用save(不带validation: false),因为这样在持久化之前不会发生有效的验证- 但是,那么您将失去从子级(通过)获取父级的能力。您仍然可以从父级(通过)访问子级。belongs_to :parentchild.rbparent_idchild.parentparent.child
试试这个:
class Child < ApplicationRecord
belongs_to :parent, optional: true
end
Run Code Online (Sandbox Code Playgroud)
在做了一些研究之后,我发现 Rails 5 现在需要一个关联的 id 在默认情况下存在于孩子中。否则 Rails 会触发验证错误。
...并且官方的 Rails指南非常简短地提到了它:
4.1.2.11 : 可选
如果您将 :optional 选项设置为 true,则不会验证关联对象的存在。默认情况下,此选项设置为 false。
所以你可以通过optional: true在belongs_to对象后面添加来关闭这个新行为。
因此,在您的示例中,您必须先创建/保存 Parent,然后再构建孩子,或使用 optional: true
| 归档时间: |
|
| 查看次数: |
1680 次 |
| 最近记录: |