12

我的完整代码可以在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,但我认为这不应该与这个问题有关。

4

3 回答 3

11

这是回调链中的“竞赛条件”。

当您创建产品时,它在保存之前没有任何 id,因此product没有ProductCategory.

Product.new(name: "modern times", category_ids:[1, 2]) #=> #<Product id: nil >

在验证的那个阶段(保存之前),ProductCatgory不能将任何 id 分配给它的外键product_id

这就是您进行关联验证的原因:因此验证发生在整个事务的范围内

更新:正如评论中所说,您仍然无法确保产品/类别的存在。有很多方法取决于您为什么要这样做(例如,通过某种形式直接访问 ProductCategory)

  • 您可以创建一个标志来拥有validates :product, presence: true, if: :direct_access?
  • 或者如果您只能更新它们:validates :product, presence: true, on: "update"
  • 首先创建您的产品(在 products_controller 中)并在之后添加类别

...但实际上这些都是简单的妥协或解决方法@product.create(params)

于 2013-01-09T09:48:03.833 回答
10

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

于 2015-07-31T16:02:52.463 回答
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
于 2013-01-07T04:24:11.010 回答