35

親モデルのフォームで属性が空白になっている場合、ネストされたモデルを破棄したいと思いますが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])行は、空のエンティティを更新する価値があるとは見なしていません。

何か不足していますか?これを回避する方法はありますか?

4

5 に答える 5

79

: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?)
于 2012-12-08T03:47:14.093 に答える
9

今日はこんな感じでできました。@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? || tour_date.where.blank?
        tour_date.mark_for_destruction
      end
    end
  end
end
于 2012-10-02T17:46:20.887 に答える
6

「where」または「when」が空白の場合、レコードを無視する必要があることを示すコードがあり、accepts_nested _attributes 行で、を削除するreject_ifと、destroy_if 空白が呼び出される可能性があります。

通常、破棄するには _destroy、ネストされたレコードに属性を設定します。ドキュメントhttp://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.htmlを確認してください。

また、今日、これのいくつかに cocoon を使用したところ、すばらしいと思いました

于 2012-06-08T04:29:11.333 に答える
5

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
于 2014-12-06T23:42:47.780 に答える
1

reject_ifに渡されたオプションのため、現在のコードでは不可能accepts_nested_attributes_forです。

Christ Mohr が言ったように、最も簡単な方法は_destroy、親を更新するときにネストされたモデルの属性を設定することであり、ネストされたモデルは破棄されます。詳細については、ドキュメントまたはこの railscastを参照してください。

または、cocoon、awesome_nested_fields などの gem を使用できます。

具体的に必要なことを行うには、reject_ifオプションを削除し、親オブジェクト内のコールバックでロジックを処理する必要があります。tour_dates_attributes の空白値をチェックし、ネストされたモデルを破棄する必要があります。でも慎重に…。

于 2012-06-08T07:38:57.200 に答える