![](/style/images/good.png)
![](/style/images/bad.png)
accepts_nested_attributes_for 的验证问题
source link: https://mednoter.com/nested_attributes_validates.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
accepts_nested_attributes_for 的验证问题
出于性能的考虑,对商品表做了垂直分割,用两张表来保存商品的信息。
-
商品的概览(products)
id title price -
商品的图文介绍(products_details)
id product_id description
为了在一个表单中保存编辑两个对象,我使用了 Rails 的 nested attributes。
Model
class Product < ActiveRecord::Base
has_one :product_detail, dependent: :destroy
attr_accessible :title, :price, product_detail_attributes
accepts_nested_attributes_for :product_detail
end
class ProductDetail < ActiveRecord::Base
belong_to :product
#此处是个坑
#validates :product_id, presence: true
end
<%= simple_form_for [:admin, product] do |f| %>
<%= f.input :title, label: "产品名"%>
<%= f.input :price, label: "市场价" %>
<%= f.simple_fields_for :product_detail do |detail| %>
<%= detail.input :markdown_description, label: "产品描述", as: :text %>
<% end -%>
<% end -%>
Controller
def new
@product = Product.new
# 如果是 has one,则使用 build_** 初始化
@product_detail = @product.build_product_detail
# 如果是 has many,则使用 *s.build 初始化
# @promotion = @product.promotions.build
end
def create
@product = Product.new(params[:product])
if @product.save
redirect_to @product
else
render ‘edit’
end
end
当 @product.save 时,二个对象的创建被包裹在一个事务中,同时创建。
part1. 创建 product
part2. 创建 product_detail
(0.2ms) BEGIN
SQL (0.3ms) INSERT INTO `products` ...
SQL (0.4ms) INSERT INTO `product_details` ...
(206.7ms) COMMIT
一个和验证相关的 bug
一开始的时候 product 和 product_detail 总是无法同时创建,log 打印出错误信息 ‘product_detail 的 product_id 不能为空’。
花了 2h 排插各种错误,无果。
class ProductDetail < ActiveRecord::Base
belong_to :product
# 注释掉后就可以保存 product_detail了
validates :product_id, presence: true
end
后来发现是一个狗血的验证导致的。
为什么这个验证会导致创建失败呢? product_detail 有 product_id 这个属性啊?
后来 Vincent 指点:
-
product 和 product_detail 创建时,会整体上检查对象是否有效(valid?)
-
此时 product 还没有创建, product_detail 无法获得 prodcut_id
-
所以 product_detail 验证失败。
如果两个对象的创建包裹在一个事务中时,第二个对象的某些属性可能暂时为空,导致验证失败?
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK