Peege151
Peege151

Reputation: 1560

ActiveRecord Rescue from View

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

Answers (1)

user419017
user419017

Reputation:

This is based on our running conversation, here:

https://chat.stackoverflow.com/rooms/55591/discussion-between-peege151-and-damien-roche


1. Update your 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| %>

2. As 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.


3. Move destroy/archive_cart logic into your models

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

Related Questions