在validation外键时,Accept_nested_attributes_for出现问题

我正在使用Ruby on Rails v3.2.2。 我想在使用accepts_nested_attributes_forvalidates_associated RoR方法时解决与validation外键有关的问题。 也就是说,我有以下模型类:

 class Article  'category_id' accepts_nested_attributes_for :category_associations, :reject_if => lambda { |attributes| attributes[:category_id].blank? } validates_associated :category_associations end class CategoryAssociation  'article_id' belongs_to :category, :foreign_key => 'category_id' validates :article_id, :presence => true validates :category_id, :presence => true end 

……我有以下控制器动作:

 class ArticlesController < ApplicationController def new @article = Article.new 5.times { @article.category_associations.build } # ... end def create @article = Article.new(params[:article]) if @article.save # ... else # ... end end end 

使用上面的代码(由“ 嵌套模型表单第1部分 Rails Cast”启发), 我的意图是在创建文章时存储类别关联注意 :类别对象已存在于数据库中;在我的情况下,我只想存储 – 创建类别协会)。 但是,当我从相关的视图文件中提交相关表单时,我收到以下错误(我正在记录错误消息):

 {:"category_associations.article_id"=>["can't be blank"], :category_associations=>["is invalid"]} 

为什么它发生,因为validates_associated 似乎运行方法article.category_association.valid? 但只有当article.category_association.article_id 不是 nil ? 如何通过article_id外键的状态validation来解决问题?

但是,如果我在CategoryAssociation模型类中注释掉validates :article_id, :presence => true ,它会按预期工作,但似乎不是一种validation外键的正确方法 。


如果我在Article模型类中注释掉validates_associated :category_associations ,我仍然会收到错误:

 {:"category_associations.article_id"=>["can't be blank"]} 

使用inverse_of链接关联,然后validation关联对象的存在,而不是实际外键的存在。

来自文档的示例:

 class Member < ActiveRecord::Base has_many :posts, inverse_of: :member accepts_nested_attributes_for :posts end class Post < ActiveRecord::Base belongs_to :member, inverse_of: :posts validates_presence_of :member end 

由于您有一个可能的嵌套表单,其中包含accepts_nested_attributes_for,因此在CategoryAssociation中,您需要使validation成为条件,要求仅存在仅用于更新:

validates :article_id, presence: true, on: :update

除了Active Record关联,您应该在db级别具有外键约束。

validation将在createsave时运行(正如您所期望的那样),因此请问自己,“在每个中都有一个被保存的实例被引用?”,因为没有保存,实例将没有id,因为它是分配id的数据库。


编辑:就像我在评论中所说的那样,如果你要进行投票,那就留下评论原因。