当父级已经保存时,如何处理无效的has_many子级的验证?

时间:2013-05-26 13:02:39

标签: ruby-on-rails ruby

我有这两个类:

class Article < ActiveRecord::Base
  has_many :article_tags
  has_many :tags, through: :article_tags
end
class ArticleTag < ActiveRecord::Base
  belongs_to :article
  belongs_to :tag
end
class Tag < ActiveRecord::Base
  validates :name, format: /\A\p{Alpha}*\z/
end

现在我在文章中添加无效标记:

这有效:

item = Item.new
item.tags << Tag.new(name: '1&+')
item.valid?                         # Returns false

但这不是

item = Item.find(params[:id])
item.tags << Tag.new(name: '1&+')   # Exception here!

原因是 - 如果项目已存在于数据库中 - <<方法会自动使用save!保存新标记。

我想要的是具有验证错误的项目,就像在第一种情况下一样。

这可以实现吗?我可以在<<方法中禁用自动保存吗?

修改

问题似乎是由has_many through关联引起的。一个简单的has_many关联不会遇到同样的问题。

调用<<方法最终会在has_many_through_association.rb中失败:

def concat(*records)
  unless owner.new_record?
    records.flatten.each do |record|
      raise_on_type_mismatch(record)
      record.save! if record.new_record?                 # Exception here!
    end
  end
  super
end

1 个答案:

答案 0 :(得分:1)

我看不到你需要担心的任何事情:)

您最后一行代码将通过。没有问题,因为标记对象不会持久存在 - 它是new

该项目在数据库中,但新的“tag”对象不在。它只在内存中。只有在尝试将对象保存到db中时才会触发验证规则。

在控制台中尝试:

> item = Item.find(params[:id])
> item.tags << Tag.new(name: '1&+') 
> item.tags[0]
#=> #<Tag:abcd0123> {
#  id: nil
#  name: '1&+'
#  ....
# } 
> item.tags[0].save!
#=> ActiveRecord::RecordInvalid: Validation failed