John
John

Reputation: 137

How to skip saving a record after destroying the record

I created a cart where a user can increment and decrement an item's quantity. There's a problem when decrementing an item's quantity one by one. For example when I have "2x Pizza", where 2 is the quantity of the pizza, I decrement its quantity by one. So then I have "1x Pizza". When I again decrement the quantity, I get an error can't modify frozen Hash.

My code:

def RemoveItemQuantity
  @cart      = current_cart
  menu       = Menu.find(params[:menu_id])
  @line_item = @cart.sub_menu(menu.id)

  if @line_item != nil
    respond_to do |format|
      if @line_item.save
        # ...
      end
    end
  end
end

def sub_menu(menu_id)
  current_item = line_items.where(:menu_id => menu_id).first

  if current_item
    current_item.quantity -= 1
  end

  if current_item.quantity == 0
    current_item.destroy
  end

  current_item
end

When the quantity of an item becomes 0, I destroy the current_item. After this it cannot save the record because of the can't modify frozen Hash error. What am I doing wrong here?

Upvotes: 0

Views: 100

Answers (2)

fivedigit
fivedigit

Reputation: 18672

The error happens because you're trying to save the destroyed record. I guess the easiest way to solve the problem is to make sure the saving and destroying happens in the same place.

You can refactor the code method a bit:

def remove_item_quantity
  @cart      = current_cart
  menu       = Menu.find(params[:menu_id])
  @line_item = line_items.where(:menu_id => menu_id).first

  if @line_item
    respond_to do |format|
      if @cart.sub_menu(@line_item)
        # ...
      end
    end
  end
end

def sub_menu(current_item)
  if current_item.quantity > 1
    current_item.update(quantity: current_item.quantity - 1)
  else
    current_item.destroy
  end
end

Notice that I look up @line_item in remove_item_quantity. Since you're already checking if the item exists, I moved the call to sub_menu inside the respond_to block.

sub_menu simply checks if the item has a quantity higher than 1. If it does, it decrements by one and saves the record. If the quantity is 1, it will become 0 when decrementing, so it's destroyed without updating the counter.

sub_menu now always returns true when either saving or destroying the record has succeeded.

Upvotes: 1

6ft Dan
6ft Dan

Reputation: 2435

I believe you can't do in-place mathematical assignment to ActiveRecord Objects. You need an appropriate update method.

Try changing:

current_item.quantity -= 1

To:

current_item.update_column( :quantity, current_item.quantity - 1 )

Upvotes: 0

Related Questions