我想销毁一个嵌套模型,如果它的属性在父模型的表单中被消隐了 - 但是,如果模型是空白的话,似乎不会调用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
和
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
我有一个艺术家的表格,使用fields_for
来显示艺术家相关旅行日期的字段,这些字段用于编辑和添加新的旅行日期,但是如果我只是删除一个旅行日期(删除它) ),永远不会调用destroy_if_blank
。据推测,Artist控制器的@artist.update_attributes(params[:artist])
行不会考虑值得更新的空白实体。
我错过了什么吗?有办法解决这个问题吗?
答案 0 :(得分:68)
我会保留:reject_if块,但是插入:_destroy =&gt;如果满足您的条件,则进入属性哈希值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?)
答案 1 :(得分: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
答案 2 :(得分: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
答案 3 :(得分:3)
与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
答案 4 :(得分:1)
由于传递给reject_if
的{{1}}选项,目前的代码无法使用。
正如基督莫尔所说,最简单的方法是在更新父项时为嵌套模型设置accepts_nested_attributes_for
属性,并且将销毁嵌套模型。有关详细信息,请参阅文档,或this railscast。
或者您可以使用像cocoon或者awesome_nested_fields这样的宝石。
要具体执行您想要的操作,您应该删除_destroy
选项,并在父对象内的回调中处理逻辑。它应该检查tour_dates_attributes中的空白值并销毁嵌套模型。但要谨慎行事......