Rails 4 级联保存关联 belongs_to 验证

Rails 4 cascade save association with validation on belongs_to

我在自动保存以这种方式创建的对象时遇到了问题。考虑使用以下模型:

class SearchTerm < ActiveRecord::Base
   has_many :search_term_occurrences, dependent: :destroy
end

class SearchTermOccurrence < ActiveRecord::Base
   belongs_to :search_term
   validates :search_term, presence: true # Problematic validation
   validates_associated :search_term # See Gotchas in answer
end

所以当我尝试执行以下操作时:

term = SearchTerm.new term: 'something'
term.search_term_occurrences << [SearchTermOccurrence.new, SearchTermOccurrence.new]
term.save!

我得到以下信息:

ActiveRecord::RecordInvalid: Validation failed: Search term occurrences is invalid, Search term occurrences is invalid

但是当我在 belongs_to search_term 上省略验证时。一切都妥善保存。

我的问题是:如何保存父对象及其关联(新创建的),同时对子对象进行验证,而不是一个一个地保存关联对象,然后在事务中保存父对象?我希望 Rails 处理事务逻辑。

您应该先保存 term 实例,然后再将 SearchTermOccurrence 对象添加到其中。

term = SearchTerm.new term: 'something' term.save! term.search_term_occurrences << [SearchTermOccurrence.new, SearchTermOccurrence.new]

因为 SearchTermOccurrence 验证其父 SearchTerm 为真,所以 SearchTerm.new 在保存之前不会将 SearchTerm 的任何 ID 创建到数据库中。

试试上面的代码

所以在玩了 Rails 控制台之后,我找到了答案。问题是保存的顺序。

我选择了不同的保存方法:我尝试从下往上保存它,而不是从上到下(SearchTerm has_many -> SearchTermOccurrences)(SearchTermOccurrence belongs_to -> SearchTerm) .所以不要这样做:

term = SearchTerm.new term: 'something'
term.search_term_occurrences << [SearchTermOccurrence.new, SearchTermOccurrence.new]
term.save!

我这样做了:

occurrence = SearchTermOccurrence.new
occurence.search_term = SearchTerm.new(term: 'search query')
occurence.save!

这突然奏效了。所以我猜测 Rails 只能在新创建时验证 belongs_to 关联中的父记录,但不能验证 has_many 子记录。

编辑 1

陷阱:

如果您选择这种级联保存方法,请确保为 belongs_to 记录添加 validates_associated 否则您可能会得到不一致的数据库,因为 validates :search_term, presence: true 即使 SearchTerm 也可以通过本身是无效的。我已将 validates_associated 添加到 SearchTermOccurrence。