我有以下型号:
class Product < ActiveRecord::Base
belongs_to :brand
belongs_to :model
accepts_nested_attributes_for :brand, :model
...
end
class Brand < ActiveRecord::Base
has_many :products
has_many :models
...
end
class Model < ActiveRecord::Base
has_many :products
belongs_to :brand
accepts_nested_attributes_for :brand
...
end
创建新产品时遇到问题。
以下是控制器中的相关代码:
class ProductsController < ApplicationController
...
def create
@product = Product.new(params[:product])
if @product.save ... # Here is the error
end
...
end
当用户添加新品牌和新模型时,params[:product]
包含以下内容:
"brand_attributes"=>{"name"=>"my_new_brand"}
"model_attributes"=>{"model_no"=>"my_new_model"}
我收到以下错误:
Mysql2::Error: Column 'brand_id' cannot be null: INSERT INTO `models` ...
因为模型具有未设置的外键brand_id
。我无法设置它,因为品牌(如模型)是在创建产品时即时创建的。我不想在产品之前创建品牌,因为那时我产品有错误,我需要删除创建的品牌。
然后我尝试像这样更改params[:product]
:
"brand_attributes"=>{"name"=>"my_new_brand",
"model_attributes"=>{"model_no"=>"my_new_model"}}
但我最终得到了这个:
unknown attribute: model_attributes
处理此问题的正确方法是什么?
答案 0 :(得分:2)
1。)你应该避免使用Model作为模型名称(我想你可以看到为什么这会导致错误,虽然我不认为这是你的问题)
2。)你引用了太多的圆形图案。产品有模型,模型有品牌。为什么你的产品属于模特和品牌?我建议进行以下设置:
class Product < ActiveRecord::Base
belongs_to :model
accepts_nested_attributes_for :model
end
class Brand < ActiveRecord::Base
has_many :models
end
class Model < ActiveRecord::Base
has_many :products
belongs_to :brand
accepts_nested_attributes_for :brand
end
我对你的数据结构感到有点困惑 - 这是你的根本问题。
Product < Model <> Brand
当您拥有上面定义的循环引用时,您不能拥有NESTED表单,因为您的模型已嵌套...
# schema
create_table :products do |t|
t.string :name
t.references :model
end
create_table :brands do |t|
t.string :name
end
create_table :models do |t|
t.string :name
t.references :brand
end
答案 1 :(得分:1)
嗯,首先,如果您将保存包装在一个事务中,则事务中任何一点的失败都会回滚所有写入,因此您的品牌等不会受到影响。
Product.transaction do
@product.save
end
你可以试试这个:
before_create :save_associated
validates_associated :brand, :model
def save_associated
brand.save if brand.new_record?
model.save if model.new_record?
end
当您创建产品记录时,它将做什么,它将验证自己,然后它将验证附加的品牌和型号。如果一切顺利,它将继续你的before_save回调,这将保存你的相关模型,然后你的产品模型将被保存。如果这三个模型中的任何一个无效,您将永远不会到达save_associated
,如果您感觉有额外的偏执,您可以将保存包装在如上所示的交易中,以自动回滚任何更改(如果有任何部分)保存失败。