before_destroy не стреляет из update_attributes - PullRequest
7 голосов
/ 22 августа 2010

У меня есть студент, у которого много курсов. В действии и форме обновления # ученика я принимаю список course_ids. Когда этот список меняется, я бы хотел вызвать определенную функцию. Код, который у меня есть , вызывается , если update_attributes создает course_student, но не вызывается , если update_attributes уничтожает course_student. Могу ли я заставить это выстрелить, или я должен сам обнаружить изменения?

# app/models/student.rb
class Student < ActiveRecord::Base
  belongs_to :teacher
  has_many :grades
  has_many :course_students, :dependent => :destroy
  has_many :courses, :through => :course_students
  has_many :course_efforts, :through => :course_efforts

  # Uncommenting this line has no effect:
  #accepts_nested_attributes_for :course_students, :allow_destroy => true

  #attr_accessible :first_name, :last_name, :email, :course_students_attributes

  validates_presence_of :first_name, :last_name
...
end

# app/models/course_student.rb
class CourseStudent < ActiveRecord::Base
  after_create  :reseed_queues
  before_destroy :reseed_queues

  belongs_to :course
  belongs_to :student

  private

  def reseed_queues
    logger.debug "******** attempting to reseed queues"
    self.course.course_efforts.each do |ce|
      ce.reseed
    end
  end

end

# app/controllers/students_controller.rb

  def update
    params[:student][:course_ids] ||= []
    respond_to do |format|
      if @student.update_attributes(params[:student])
        format.html { redirect_to(@student, :notice => 'Student was successfully updated.') }
        format.xml  { head :ok }
      else
        format.html { render :action => "edit" }
        format.xml  { render :xml => @student.errors, :status => :unprocessable_entity }
      end
    end
  end

Ответы [ 6 ]

7 голосов
/ 16 декабря 2010

Оказывается, что это поведение задокументировано прямо на методе has_many .Из документации API:

collection = objects Заменяет содержимое коллекций, удаляя и добавляя объекты соответствующим образом.Если опция: through имеет значение true, обратные вызовы в моделях объединения запускаются, кроме как уничтожить обратные вызовы, поскольку удаление является прямым.

Я не уверен, что означает «поскольку удаление является прямым», но тамэто.

1 голос
/ 15 сентября 2017

Когда запись удаляется с использованием update / update_attributes, она запускает метод delete вместо destroy.

@student.update_attributes(params[:student])

Delete метод пропуск обратные вызовы и, следовательно, after_create / before_destroy не будут вызваны.Вместо этого можно использовать accepts_nested_attributes_for , который удаляет запись и поддерживает обратные вызовы.

accepts_nested_attributes_for :courses, allow_destroy: true

@student.update_attributes(courses_attributes: [ {id: student_course_association_id, _destroy: 1 } ])

1 голос
/ 24 августа 2015

Если вы добавите dependent: :destroy, это будет выполнено.Обратите внимание, что если вы используете has_many through:, нужно добавить эту опцию к обоим.

  has_many :direct_associations, dependent: :destroy, autosave: true
  has_many :indirect_associations, through: :direct_associations, dependent: :destroy

(я использовал это в Rails 3, держу пари, это будет работать и на Rails 4)

1 голос
/ 23 августа 2010

Принимает вложенные атрибуты, требует флаг для запуска вложенного уничтожения.По крайней мере, это было когда.

0 голосов
/ 15 декабря 2010

Не удалось оставить комментарий, поэтому я просто добавлю запись ответа.

Только что столкнулся с той же ошибкой. После нескольких часов попыток разобраться в этой проблеме и часа поисков в Google, я случайно наткнулся на этот вопрос. Наряду со связанным билетом LH и цитатой из API, теперь это имеет смысл. Спасибо!

Пока гуглил, нашел старый билет. Прямая ссылка не работает, но у кеша гугл есть копия. Просто проверьте Google на наличие кешированной версии dev.rubyonrails.org/ticket/7743

Похоже, патч так и не попал в Rails.

0 голосов
/ 22 августа 2010

Если ваш CourseStudent указывает belongs_to :student, :dependent => :destroy, создается впечатление, что запись CourseStudent была бы недействительной без студента.

Попытка следовать обсуждению LH, на которое я ссылался выше, и это Я бы также попытался переместить обратный вызов before_destroy в CourseStudent ниже belongs_to.Связанный пример демонстрирует, как порядок обратных вызовов имеет значение с after_create, возможно, то же самое относится к before_destroy.И, конечно же, поскольку вы используете Edge Rails, я бы также попробовал RC, возможно, там была исправлена ​​ошибка.

В противном случае я бы попытался создать действительно простое приложение на Rails сдве модели, которые демонстрируют проблему и отправляют ее на Rails 'Lighthouse.

...