2012-06-08 58 views
26

我想摧毀一個嵌套模式,如果它的屬性形式父模型削除 - 然而,它看來,如果該模型是空白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.update_attributes(params[:artist])行不考慮值得更新的空白實體。

我錯過了什麼嗎?有沒有解決的辦法?

回答

1

由於reject_if選項傳遞給accepts_nested_attributes_for,所以使用當前的代碼是不可能的。

正如Christ Mohr所說,最簡單的方法是在更新父代時爲嵌套模型設置_destroy屬性,並且嵌套模型將被銷燬。請參閱文檔以瞭解更多信息,或者this railscast

或者你可以使用像繭或awesome_nested_fields寶石。

要明確你想要什麼,你應該刪除reject_if選項,以及如何在父對象中的回調邏輯。它應該檢查tour_dates_attributes中的空白值並銷燬嵌套模型。但仔細踩...

5

我設法做今天這樣的事情。就像@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 
+0

爲什麼有'tour_date.when.blank?兩次?謝謝 –

+0

@maxkaplan:應該是'when'和'where'。我將它固定在答案中。謝謝! – Sunny

61

我會保留:reject_if塊,但插入:_destroy => 1到屬性哈希,如果你的條件得到滿足。 (這是在它的不方便_destroy添加到表單代碼的情況下非常有用。)

你要做額外的檢查,看是否以返回正確的價值存在記錄,但以下似乎工作在所有情況下對我來說。

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

這是一個輝煌的解決方案,但是,你需要確保驗證關閉相關的模型或它似乎無法對新記錄。 – JoshL

+3

它不應該失敗的新紀錄,因爲新的記錄不應該有一個'id'屬性,嵌套的記錄將被拒​​絕,並不會加載。這個解決方案很棒我通過執行'empty = attributes.reject {| k,v |'來略微修改它k =='id'}。values.all?(&:blank?)'檢查所有空屬性。 – DGM

+2

我愛你這麼多,現在 –

2

史蒂夫·肯沃西的答案相似,無局部變量:

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計算,你可以申請。

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 
+0

「這是一個非常好的」 –