Destroy on blank nested attribute

前端 未结 5 1066
醉酒成梦
醉酒成梦 2020-12-13 09:36

I would like to destroy a nested model if its attributes are blanked out in the form for the parent model - however, it appears that the ActiveRecord::Callbacks

相关标签:
5条回答
  • 2020-12-13 09:50

    I managed to do something like this today. Like @shuriu says, your best option is to remove the reject_if option and handle destruction yourself. mark_for_destruction comes in handy :

    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
    
    0 讨论(0)
  • 2020-12-13 09:51

    I would keep the :reject_if block but insert :_destroy => 1 into the attributes hash if your conditions are met. (This is useful in the cases where it's not convenient to add _destroy to the form code.)

    You have to do an extra check to see if the record exists in order to return the right value but the following seems to work in all cases for me.

    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
    

    You could apply when all attributes are blank by just changing the empty calculation to:

    empty = attributes.except(:id).values.all?(&:blank?)
    
    0 讨论(0)
  • 2020-12-13 09:55

    With your current code it's not possible, because of the reject_if option passed to accepts_nested_attributes_for.

    As Christ Mohr said, the easiest way is to set the _destroy attribute for the nested model when updating the parent, and the nested model will be destroyed. Refer to the docs for more info on this, or this railscast.

    Or you can use a gem like cocoon, or awesome_nested_fields.

    To do specifically what you want, you should remove the reject_if option, and handle the logic in a callback inside the parent object. It should check for blank values in the tour_dates_attributes and destroy the nested model. But tread carefully...

    0 讨论(0)
  • 2020-12-13 10:02

    You have code that says the record should be ignored if the 'where' or the 'when' is blank, on the accepts_nested _attributes line, remove the reject_if and your destroy_if blank will likely be called.

    Typically to destroy, you would set a _destroy attribute on the nested record, check out the docs http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html

    Also, just used cocoon for some of this today, and thought it was awesome, https://github.com/nathanvda/cocoon

    0 讨论(0)
  • 2020-12-13 10:10

    Similar to Steve Kenworthy's answer, no local variables.

     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 讨论(0)
提交回复
热议问题