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。
我在自动保存以这种方式创建的对象时遇到了问题。考虑使用以下模型:
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。