【问题标题】:Failing validations in join model when using has_many :through使用 has_many 时连接模型中的验证失败:通过
【发布时间】:2013-01-03 14:38:52
【问题描述】:

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

【问题讨论】:

  • 您是否从ProductCategory 模型中删除了此validates_associated 并尝试保存@product.save!因为这是没有必要的。
  • 是的,我试过了,但没有用。

标签: ruby-on-rails activerecord


【解决方案1】:

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

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

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)的妥协或变通方法

【讨论】:

  • 好的,这很有道理。但是当我在 :product 和 :category 上指定 validates_associated 时,这不会阻止在没有这些关联的情况下创建 ProductCategory。
  • 我已更新帖子以解决您的评论。哦,您还可以覆盖 category_ids=(array) 以在关联之前保存产品...但是除了必须编写更多代码之外,我没有看到其他任何内容...
【解决方案2】:

已记录在您的加入模型上指定 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

【讨论】:

    【解决方案3】:

    很确定您只需要更好地定义您的关系。我可能仍然错过了一些,但希望你能明白。

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-20
      • 1970-01-01
      • 2016-07-24
      • 2019-06-22
      • 1970-01-01
      • 1970-01-01
      • 2017-03-30
      • 1970-01-01
      相关资源
      最近更新 更多