Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

shopping cart, possible to use Devise's session functionality?

I am writing an ecommerce website and I need to implement a shopping cart feature. I want the customers to be able to add products to their cart without signing up beforehand, so I figured I would accomplish this through sessions.

Can this be done in the Devise gem or will I have to implement my own session model for this to work?

like image 752
manis Avatar asked Apr 18 '14 12:04

manis


1 Answers

You'll need to handle your own session data - doesn't mean you'll need a session model though.

We've implemented what you're looking for. It works using a session model, but uses the same base functionality I'd recommend for you:

#app/models/cart_session.rb
class CartSession

    #Initalize Cart Session
    def initialize(session)
        @session = session
        @session[:cart] ||= {}
    end

    #Cart Count
    def cart_count
        if (@session[:cart][:products] && @session[:cart][:products] != {})
            @session[:cart][:products].count
        else
            0
        end
    end

    #Cart Contents
    def cart_contents
        products = @session[:cart][:products]

        if (products && products != {})

            #Determine Quantities
            quantities = Hash[products.uniq.map {|i| [i, products.count(i)]}]

            #Get products from DB
            products_array = Product.find(products.uniq)

            #Create Qty Array
            products_new = {}
            products_array.each{
                |a| products_new[a] = {"qty" => quantities[a.id.to_s]}
            }

            #Output appended
            return products_new

        end

    end

    #Qty & Price Count
    def subtotal
        products = cart_contents

        #Get subtotal of the cart items
        subtotal = 0
        unless products.blank?
            products.each do |a|
                subtotal += (a[0]["price"].to_f * a[1]["qty"].to_f)
            end
        end

        return subtotal

    end

    #Build Hash For ActiveMerchant
    def build_order

        #Take cart objects & add them to items hash
        products = cart_contents

        @order = []
        products.each do |product|
            @order << {name: product[0].name, quantity: product[1]["qty"], amount: (product[0].price * 100).to_i }
        end

        return @order
    end

    #Build JSON Requests
    def build_json
        session = @session[:cart][:products]
        json = {:subtotal => self.subtotal.to_f.round(2), :qty => self.cart_count, :items => Hash[session.uniq.map {|i| [i, session.count(i)]}]}
        return json
    end

  
end

Sessions

According to the Rails documentation:

Most applications need to keep track of certain state of a particular user. This could be the contents of a shopping basket or the user id of the currently logged in user. Without the idea of sessions, the user would have to identify, and probably authenticate, on every request. Rails will create a new session automatically if a new user accesses the application. It will load an existing session if the user has already used the application.

Sessions, to my knowledge, are small cookie files storing data for each user. These are ambiguous (are created for every user - regardless of whether they are signed in or not), which means I'd use them for your cart

We use Sessions to create cart data by storing raw id's of the cart products in the session


Devise

A note on Devise - what you're asking about has nothing to do with the Devise gem. Devise is an authentication system, meaning it handles if a user has access to your app; it doesn't handle shopping cart data

Whilst Devise stores data in sessions, you'll need to define your own session data for your cart. We do this using a cart controller with the model code above:

#config/routes.rb
get 'cart' => 'cart#index', :as => 'cart_index'
post 'cart/add/:id' => 'cart#add', :as => 'cart_add'
delete 'cart/remove(/:id(/:all))' => 'cart#delete', :as => 'cart_delete'

#app/controllers/cart_controller.rb
class CartController < ApplicationController
    include ApplicationHelper

    #Index
    def index
        @items = cart_session.cart_contents
        @shipping = Shipping.all
    end

    #Add
    def add
        session[:cart] ||={}
        products = session[:cart][:products]

        #If exists, add new, else create new variable
        if (products && products != {})
            session[:cart][:products] << params[:id]
        else
            session[:cart][:products] = Array(params[:id])
        end

        #Handle the request
        respond_to do |format|
            format.json { render json: cart_session.build_json }
            format.html { redirect_to cart_index_path }
        end
    end

    #Delete
    def delete
        session[:cart] ||={}
        products = session[:cart][:products]
        id = params[:id]
        all = params[:all]

        #Is ID present?
        unless id.blank?
            unless all.blank?
                products.delete(params['id'])
            else
                products.delete_at(products.index(id) || products.length)
            end
        else
            products.delete
        end

        #Handle the request
        respond_to do |format|
            format.json { render json: cart_session.build_json }
            format.html { redirect_to cart_index_path }
        end
    end

end
like image 107
Richard Peck Avatar answered Nov 15 '22 05:11

Richard Peck