我的完整代码可以在https://github.com/andyw8/simpleform_examples
看到我有一个联接模型ProductCategory
,其中包含以下验证:
validates :product, presence: true
validates :category, presence: true
我的Product
模型具有以下关联:
has_many :product_categories
has_many :categories, through: :product_categories
当我尝试使用类别创建新产品时,控制器中对@product.save!
的调用将失败:
Validation failed: Product categories is invalid
删除验证后,一切正常,连接模型也会正确保存。
我正在使用strong_parameters
,但我认为应与此问题相关。
答案 0 :(得分:11)
这是回调链中的“竞争条件”。
创建产品时,在保存之前它没有任何ID,因此product
范围内没有ProductCategory
。
Product.new(name: "modern times", category_ids:[1, 2]) #=> #<Product id: nil >
在验证阶段(保存之前),ProductCatgory
无法为其外键product_id
分配任何ID。
这就是你有关联验证的原因:这样验证就发生在整个交易的范围内
更新:正如评论中所说,您仍然无法确保产品/类别的存在。有很多方法取决于你想要这样做的原因(例如通过某种形式直接访问ProductCategory)
validates :product, presence: true, if: :direct_access?
validates :product, presence: true, on: "update"
......但事实上,这些都是简单@product.create(params)
答案 1 :(得分:3)
已记录在您的加入模型上指定inverse_of
以解决此问题:
https://github.com/rails/rails/issues/6161#issuecomment-6330795 https://github.com/rails/rails/pull/7661#issuecomment-8614206
简化示例:
class Product < ActiveRecord::Base
has_many :product_categories, :inverse_of => :product
has_many :categories, through: :product_categories
end
class Category < ActiveRecord::Base
has_many :product_categories, inverse_of: :category
has_many :products, through: :product_categories
end
class ProductCategory < ActiveRecord::Base
belongs_to :product
belongs_to :category
validates :product, presence: true
validates :category, presence: true
end
Product.new(:categories => [Category.new]).valid? # complains that the ProductCategory is invalid without inverse_of specified
改编自:https://github.com/rails/rails/issues/8269#issuecomment-12032536
答案 2 :(得分:0)
非常确定您需要更好地定义您的关系。我仍然可能错过了一些,但希望你能得到这个想法。
class Product < ActiveRecord::Base
include ActiveModel::ForbiddenAttributesProtection
validates :name, presence: true
validates :description, presence: true
validates :color_scheme, presence: true
belongs_to :color_scheme
has_many :product_categories, inverse_of: :product
has_many :categories, through: :product_categories
end
class ProductCategory < ActiveRecord::Base
belongs_to :product
belongs_to :category
validates_associated :product
validates_associated :category
# TODO work out why this causes ProductsController#create to fail
# validates :product, presence: true
# validates :category, presence: true
end
class Category < ActiveRecord::Base
has_many :product_categories, inverse_of: :category
has_many :products, through: :product_categories
end