Search code examples
ruby-on-railscocoon-gem

Can't work before_validation when nested field is delated with cocoon gem


I have this migration and model for order and order_detail with cocoon gem.

class CreateOrders < ActiveRecord::Migration[5.0]
  def change
    create_table :orders do |t|
      t.integer :total_price
      t.timestamps
    end
  end
end

class CreateOrderDetails < ActiveRecord::Migration[5.0]
  def change
    create_table :order_details do |t|
      t.integer :subtotal_price
      t.integer :unit_price
      t.integer :quantity
      t.references :order, foreign_key: true
      t.timestamps
    end
  end
end

class Order < ApplicationRecord
  has_many :order_details, inverse_of: :order, dependent: :destroy
  before_validation :calculate_order_price
  accepts_nested_attributes_for :order_details, :reject_if => :all_blank, :allow_destroy => true

  def calculate_order_price
    order_details.each(&:calculate_order_detail_price)
    self.total_price = order_details.map(&:subtotal_price).sum
  end
end

class OrderDetail < ApplicationRecord
  belongs_to :order
  def calculate_order_detail_price
    self.subtotal_price = unit_price * quantity
  end
end

When I save the record after to add or edit the nested field, it works well. But if I edit to delate nested field, calculate_order_price doesn't work.

If somebody knows about this, please advise me.


Solution

  • There is an option :touch which will make sure upon update the parent sets the updated_at (or other fields) but it will not run the validations. There is however also an option :validate (but not entirely sure it will be called upon destroy):

     belongs_to :order, validate: true 
    

    Otherwise, if those not work, you could do something like

    class OrderDetail < ApplicationRecord 
    
      belongs_to :order 
    
      after_destroy :trigger_parent_validation
    
      def trigger_parent_validation 
        if order.present? 
          order.validate 
        end
      end 
    end