Подтвердить что ты не робот

Уничтожить пустые вложенные атрибуты

Я хотел бы уничтожить вложенную модель, если ее атрибуты затушеваны в форме для родительской модели, однако, похоже, что 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

У меня есть форма для Artist, которая использует fields_for для отображения полей для дат тура, связанных с художником, который работает для редактирования и добавления новых дат тура, но если я просто удалю дату тура (чтобы удалить ее) destroy_if_blank никогда не вызывается. Предположительно, строка контроллера Artist @artist.update_attributes(params[:artist]) не рассматривает пустую ценность объекта, которая должна быть обновлена.

Я что-то упустил? Есть ли способ обойти это?

4b9b3361

Ответ 1

У вас есть код, в котором говорится, что запись должна быть проигнорирована, если "where" или "когда" пусто, в строке accepts_nested _attributes, удалите reject_if, и ваш пул destroy_if, скорее всего, будет вызван.

Как правило, уничтожайте, вы должны установить атрибут _destroy на вложенную запись, проверить документы http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html

Кроме того, только что использовался кокон для некоторых из этого сегодня, и подумал, что это потрясающе, https://github.com/nathanvda/cocoon

Ответ 2

Я бы сохранил блок: 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?)

Ответ 3

Мне удалось сделать что-то подобное сегодня. Как говорит @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

Ответ 4

Подобно Стиву Кенворти, ответьте, нет локальных переменных.

 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

Ответ 5

С вашим текущим кодом это невозможно, из-за опции reject_if, переданной в accepts_nested_attributes_for.

Как сказал Христос Мор, самый простой способ - установить атрибут _destroy для вложенной модели при обновлении родителя, а вложенная модель будет уничтожена. Обратитесь к документам за дополнительной информацией об этом, или этот railscast.

Или вы можете использовать драгоценный камень, например кокон, или awesome_nested_fields.

Чтобы сделать то, что вам нужно, вы должны удалить параметр reject_if и обработать логику в обратном вызове внутри родительского объекта. Он должен проверять пустые значения в атрибутах tour_dates_attributes и уничтожать вложенную модель. Но осторожно протрите...