销毁空白嵌套属性

Chr*_*her 31 activerecord ruby-on-rails

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

class Artist < ActiveRecord::Base
  using_access_control
  attr_accessible :bio, :name, :tour_dates_attributes
  has_many :tour_dates, :dependent => :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
Run Code Online (Sandbox Code Playgroud)

class TourDate < ActiveRecord::Base
  validates :address, :when, :where, :artist_id, :presence => 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
Run Code Online (Sandbox Code Playgroud)

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

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

小智 71

我会保留: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
Run Code Online (Sandbox Code Playgroud)

您可以应用在所有的属性都是空白的只是改变了empty计算:

empty = attributes.except(:id).values.all?(&:blank?)
Run Code Online (Sandbox Code Playgroud)

  • 它不应该在新记录上失败,因为新记录不应该具有`id`属性,并且嵌套记录将被拒​​绝并且不被加载.这解决方案摇滚!我通过`empty = attributes.reject {| k,v |来稍微修改它 k =='id'}.values.all?(&:blank?)`来检查所有空属性. (3认同)
  • 这需要被标记为答案 - 太棒了:) (2认同)

小智 6

你有代码说如果'where'或'when'是空白的话应该忽略记录,在accepts_nested _attributes行上删除reject_if,你的destroy_if空白可能会被调用.

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

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


Sun*_*nny 6

我今天设法做了这样的事情.就像@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
Run Code Online (Sandbox Code Playgroud)


Mar*_*rom 5

与史蒂夫肯沃西的回答类似,没有局部变量。

 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
Run Code Online (Sandbox Code Playgroud)