我遇到有关孩子存在的has_many关系验证的问题,但父母却没有。但是,在创建/保存父对象时,我希望确保已保存特定子项(具有某些属性)。
Parent
has_many
个对象有Child
个对象。 Child
对象首先保留在数据库中,因此没有对父对象的任何引用。关联结构是:
Parent
- has_many :children
Child
- someProperty: string
- belongs_to: parent
例如,有三个子对象:
#1 {someProperty: "bookmark", parent: nil}
#2 {someProperty: "history", parent: nil }
#2 {someProperty: "window", parent: nil }
父项只有在包含具有someProperty history
和window
的子对象时才有效。
我将控制器中的父设置为:
p = Parent.new(params[:data])
for type in %w[bookmark_id history_id window_id]
if !params[type].blank?
p.children << Child.find(params[type])
end
end
// save the parent object p now
p.save!
当孩子被分配给父母<<
时,他们不会立即保存,因为父母的身份不存在。为了保存父母,它必须至少有这2个孩子。我怎么能解决这个问题?欢迎任何意见。
答案 0 :(得分:5)
不确定为什么你需要做这样的事情,但无论如何,这样做怎么样?
class Parent < ActiveRecord::Base
CHILDREN_TYPES = %w[bookmark_id history_id window_id]
CHILDREN_TYPES.each{ |c| attr_accessor c }
has_many :children
before_validation :assign_children
validate :ensure_has_proper_children
private
def assign_children
CHILDREN_TYPES.each do |t|
children << Child.find(send(t)) unless send(t).blank?
end
end
def ensure_has_proper_children
# Test if the potential children meet the criteria and add errors to :base if they don't
end
end
控制器:
...
p = Parent.new(params[:data])
p.save!
...
正如您所看到的,我首先将所有逻辑移至模型。然后,有一个两步拯救儿童的过程。首先,我们将子项分配给父项,然后验证它们是否符合所需条件(在那里插入逻辑)。
抱歉做空。如有必要,我会回答任何其他问题。
答案 1 :(得分:1)
首先,如果您希望在没有父ID的情况下保存子项,那么这样做是没有意义的
p = Parent.new(params[:data])
for type in %w[bookmark_id history_id window_id]
if !params[type].blank?
p.children << Child.find(params[type])
end
end
的全部目的
p.children << some_child
是将父ID附加到您未在此处执行的子对象,因为父级尚不存在。
另一件事是,如果您只是想确保父对象具有子对象,并且如果您一起创建子对象和父对象,那么您可以在父和子创建周围使用事务块,这将确保父对象具有孩子,像
transaction do
p = create_parent
p.children << child1
p.children << child2
end
因此,在事务中,如果在任何阶段代码失败,那么它将回滚整个数据库事务,即,如果这是您正在寻找的最终状态,您将要么有一个父项有2个子项,或者什么也没有。
编辑:因为你不能创建父母,除非它有2个孩子,在这种情况下,而不是
p = Parent.new(params[:data])
for type in %w[bookmark_id history_id window_id]
if !params[type].blank?
p.children << Child.find(params[type])
end
end
DO
children = []
for type in %w[bookmark_id history_id window_id]
if !params[type].blank?
children << Child.find(params[type])
end
end
if children.size >= 2
p = Parent.create!(params[:data])
children.each {|child| p.children << child}
end
这是否有意义