Reputation: 1560
I build a little e-commerce solution. At the end of an order, I want the cart to delete, so a user can't access the same cart after ordering. After I render the order_confirmation page, I have an after_action [:show] that deletes the cart. If refreshed, the order confirmation page won't work because the line items(items teh user bought) were destroyed with the cart.
This is fine, I already sent them an email and if they refresh the confirmation page I'd like an activerecord::recordnotfound rescue.
my view looks like this though
<% @order.items.each do |id| %>
<% @line_item = LineItem.find(id) %>
(line item data to show)
When refreshed, the line_items delete and I get an activerecord error.
Couldn't find LineItem with id=8
Since this is being called from the view, and isn't exactly conventional -- how can I rescue to redirect and say something like "Your Cart is Reset" or something along those lines? I tried putting it in the controller but it didn't get touched (or didn't trigger..)
after_action :remove_cart, only: [:show]
def index
@orders = Order.all
end
def show
@order = Order.find(params[:id])
@cart = current_cart
rescue ActiveRecord::RecordNotFound
logger.error "User Refresh Page"
redirect_to products_path
raise
end
If it's super advised not to have a loop like that in the view, should create an array in the controller and then loop through them on the view and create the rescue in the controller?
UPDATE:
remove_cart method is pretty blunt, looks like this.
def remove_cart
@cart = current_cart
@cart.destroy
end
Update
I've followed Damien's instructions but the after commit
gives me this
(6.2ms) COMMIT
undefined method `true=' for #<Cart:0x00000106b9fb98>
Redirected to http://localhost:3000/orders/8
Completed 302 Found in 1933ms (ActiveRecord: 19.4ms)
with order.rb
after_commit :archive_cart, on: :create
private
def archive_cart
cart.archive!
end
and cart.rb as
def archive!
update_attribute(active, false)
end
Upvotes: 1
Views: 661
Reputation:
This is based on our running conversation, here:
https://chat.stackoverflow.com/rooms/55591/discussion-between-peege151-and-damien-roche
Order
model to include:class Order
belongs_to :cart
has_many :line_items, through: :cart
end
Then, in your view:
<% @order.line_items.each do |line_item| %>
meager
noted, you should archive order details. Add a status to your cart, such as:add_column :carts, :active, :boolean, default: true
Then, instead of @cart = current_cart
in your controller, refer to the cart
directly via @order.cart
.
Note: this is not normal behaviour -- Order
would usually have a status
, and the cart
would be archived when that Order
is confirmed, but asker is using a preliminary model (OrderPreview
), where each new Order
is pre-confirmed.
class Order
after_commit :archive_cart, on: :create
private
def archive_cart
cart.archive!
end
end
class Cart
def archive!
update_attribute(:active, false)
end
end
Upvotes: 1