销毁空白嵌套属性

我想破坏嵌套模型,如果它的属性在父模型的表单中被消隐 – 但是,如果模型为空,则看起来不会调用ActiveRecord::Callbacks

 class Artist  :destroy accepts_nested_attributes_for :tour_dates, :reject_if => lambda { |a| a[:when].blank? || a[:where].blank? }, :allow_destroy => true validates :bio, :name :presence => true def to_param name end end 

 class TourDate  true attr_accessible :address, :artist_id, :when, :where belongs_to :artist before_save :destroy_if_blank private def destroy_if_blank logger.info "destroy_if_blank called" end end 

我有一个艺术家的表格,它使用fields_for来显示艺术家相关旅游日期的字段,这些字段用于编辑和添加新的旅行日期,但如果我只是删除旅行日期(删除它),则永远不会调用destroy_if_blank 。 据推测,艺术家控制器的@artist.update_attributes(params[:artist])行不会考虑值得更新的空白实体。

我错过了什么吗? 有没有解决的办法?

您有代码表示如果’where’或’when’为空,则应忽略该记录,在accepts_nested _attributes行上,删除reject_if并且可能会调用您的destroy_if空白。

通常要销毁,你可以在嵌套记录上设置一个_destroy属性,查看文档http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html

此外,今天只使用了一些茧,并认为它很棒, https://github.com/nathanvda/cocoon

我会保留:reject_if块,但如果满足条件,则将:_destroy => 1插入属性哈希。 (这在将_destroy添加到表单代码不方便的情况下很有用。)

您必须额外检查以查看记录是否存在以便返回正确的值,但以下似乎适用于所有情况。

 accepts_nested_attributes_for :tour_dates, :reject_if => :reject_tour, :allow_destroy => true def reject_tour(attributes) exists = attributes['id'].present? empty = attributes.slice(:when, :where).values.all?(&:blank?) attributes.merge!({:_destroy => 1}) if exists and empty # destroy empty tour return (!exists and empty) # reject empty attributes end 

只需将empty计算更改为以下所有属性为空,即可应用:

 empty = attributes.except(:id).values.all?(&:blank?) 

我今天设法做了这样的事情。 就像@shuriu说的那样,你最好的选择就是删除reject_if选项并自己处理破坏。 mark_for_destruction派上用场:

 class Artist < ActiveRecord::Base accepts_nested_attributes_for :tour_dates before_validation :mark_tour_dates_for_destruction def mark_tour_dates_for_destruction tour_dates.each do |tour_date| if tour_date.when.blank? or tour_date.where.blank? tour_date.mark_for_destruction end end end end 

与Steve Kenworthy的答案类似,没有局部变量。

  accepts_nested_attributes_for :tour_dates, :reject_if => :reject_tour, :allow_destroy => true def reject_tour(attributes) if attributes[:when].blank? || attributes[:where].blank? if attributes[:id].present? attributes.merge!({:_destroy => 1}) && false else true end end end 

使用当前代码是不可能的,因为reject_if选项传递给accepts_nested_attributes_for

正如Christ Mohr所说,最简单的方法是在更新父级时为嵌套模型设置_destroy属性,并且将销毁嵌套模型。 有关此内容或此railscast的更多信息,请参阅文档。

或者您可以使用像cocoon或awesome_nested_fields这样的gem。

要明确地执行您想要的操作,您应该删除reject_if选项,并在父对象内的回调中处理逻辑。 它应该检查tour_dates_attributes中的空白值并销毁嵌套模型。 但仔细踩……