4

我在验证子级存在但父级不存在的 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 }

仅当父对象包含具有 somePropertyhistory和的子对象时,父对象才有效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!

当孩子被分配给父母时<<,他们不会立即保存,因为父母的id不存在。而要得救的父母,它必须至少有这两个孩子。我该如何解决这个问题?欢迎任何意见。

4

2 回答 2

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!
...

如您所见,我首先将所有逻辑移至建模。然后,有一个拯救孩子的两步过程。首先,我们将孩子分配给父母,然后我们验证他们是否符合要求的标准(在此处插入您的逻辑)。

对不起,简短。如有必要,我会回答任何进一步的问题。

于 2010-02-03T09:06:13.987 回答
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

 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

那有意义吗

于 2010-02-03T06:54:47.263 回答