Giter VIP home page Giter VIP logo

ecommerce's Introduction

README

This is a capstone Rails application created as part of the Bloc curriculum.

  • It is a basic e-commerce platform connecting owners with customers.

Owners can:

  • create an online store

  • add, update, and delete products

  • view orders

Customers can:

  • sign up for an account

  • add products to cart

  • checkout and confirm order

Additional information:

  • Stripe used for payment processing.

  • Bootstrap used for styling.

  • Devise for user authentication.

ecommerce's People

Contributors

limichelle21 avatar

Watchers

 avatar  avatar  avatar

ecommerce's Issues

How to handle customer sign up/sign in/sign out

Can I use Devise to handle account sign ups at the store level?

  • Need to replace Sign Up/In links to a customer sign up route (something like if current_store.present? ? customer_sign_up_path : store_path)
  • How to modify the user paths to differentiate between owner and customer?
  • Should there even be customer accounts for each store? Can they always be guests?
    Prefix Verb   URI Pattern                                             Controller#Action
            new_user_session GET    /users/sign_in(.:format)                                users/sessions#new
                user_session POST   /users/sign_in(.:format)                                users/sessions#create
        destroy_user_session DELETE /users/sign_out(.:format)                               users/sessions#destroy
               user_password POST   /users/password(.:format)                               devise/passwords#create
           new_user_password GET    /users/password/new(.:format)                           devise/passwords#new
          edit_user_password GET    /users/password/edit(.:format)                          devise/passwords#edit
                             PATCH  /users/password(.:format)                               devise/passwords#update
                             PUT    /users/password(.:format)                               devise/passwords#update
    cancel_user_registration GET    /users/cancel(.:format)                                 users/registrations#cancel
           user_registration POST   /users(.:format)                                        users/registrations#create
       new_user_registration GET    /users/sign_up(.:format)                                users/registrations#new
      edit_user_registration GET    /users/edit(.:format)                                   users/registrations#edit
                             PATCH  /users(.:format)                                        users/registrations#update
                             PUT    /users(.:format)                                        users/registrations#update
                             DELETE /users(.:format)                                        users/registrations#destroy

Dashboard Orders#Index view

Every time the page is refreshed, a fake/new order is added. Have never seen this issue before - what is causing it?

Started GET "/dashboard/3/orders" for ::1 at 2016-08-09 19:23:14 +0800
Processing by Dashboard::OrdersController#index as HTML
  Parameters: {"store_id"=>"3"}
  Store Load (0.1ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."slug" = ?  ORDER BY "stores"."id" ASC LIMIT 1  [["slug", "3"]]
  Store Load (0.1ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."id" = ? LIMIT 1  [["id", 3]]
  CACHE (0.0ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."slug" = ?  ORDER BY "stores"."id" ASC LIMIT 1  [["slug", "3"]]
  CACHE (0.0ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."id" = ? LIMIT 1  [["id", "3"]]
  CACHE (0.0ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."slug" = ?  ORDER BY "stores"."id" ASC LIMIT 1  [["slug", "3"]]
  CACHE (0.0ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."id" = ? LIMIT 1  [["id", "3"]]
  CACHE (0.0ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."slug" = ?  ORDER BY "stores"."id" ASC LIMIT 1  [["slug", "3"]]
  CACHE (0.0ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."id" = ? LIMIT 1  [["id", "3"]]
   (0.1ms)  begin transaction
  SQL (0.3ms)  INSERT INTO "orders" ("store_id", "created_at", "updated_at") VALUES (?, ?, ?)  [["store_id", 3], ["created_at", "2016-08-09 11:23:14.672444"], ["updated_at", "2016-08-09 11:23:14.672444"]]
   (1.0ms)  commit transaction
  Store Load (0.1ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."slug" = ?  ORDER BY "stores"."id" ASC LIMIT 1  [["slug", "3"]]
  Store Load (0.1ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."id" = ? LIMIT 1  [["id", 3]]
  Order Load (0.2ms)  SELECT "orders".* FROM "orders" WHERE "orders"."store_id" = ?  [["store_id", 3]]
  Rendered dashboard/orders/index.html.erb within layouts/dashboard (2.6ms)
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ?  ORDER BY "users"."id" ASC LIMIT 1  [["id", 11]]
  Rendered layouts/_dashboard_header.html.erb (2.4ms)
  Rendered layouts/_dashboard_sidebar.html.erb (0.8ms)
Completed 200 OK in 244ms (Views: 167.2ms | ActiveRecord: 2.3ms)

Sign Up/In/Out - Issues 8.24

Owner-User (Devise)

  • Sessions#Destroy -- the user session is destroyed, but does not auto redirect to root_path (Welcome#Index)

Customer-User (custom Sessions controller)

  • [ ]Sessions#create action - undefined method authenticate on User. a Customer is retrieved correctly based on find_by. Fails on the authenticate method
def create
    user = User.find_by(email: params[:session][:email].downcase)

    if user && user.authenticate(params[:session][:password])
      create_session(user)
      flash[:notice] = "Welcome, #{user.name}!"
      redirect_to store_path(store_id: current_store.id)
    else
      flash.now[:alert] = 'Invalid email/password combination'
      render :new
    end
  end

Application Controller - current_order method

def current_order 
    @store = Store.friendly.find(params[:store_id])
    if !session[:current_order_id].nil?
      @store.orders.find_by(id: session[:current_order_id])
    else
      @store.orders.create
    end
  end

Tested this method, order_line add to cart, update quantity, and delete from cart for store_id 2, which worked for the most part (except an issue related to page refresh). Tried accessing store_id 3, adding product to cart - ran into error (@order = current_order not setting correctly)

@mjthompsgb Why would it work for one store and not the other? Is it related to session IDs across different stores?

Current_order method creating orders on every page load..!

Hi @mjthompsgb - should this method be moved out of the application controller? It seems to run every time a page is accessed, thus creating a ton of fake orders.

 def current_order 
    if current_store.present?
      if !session["current_order_id_#{current_store.id}"].nil?
        @current_order = current_store.orders.find_by(id: session["current_order_id_#{current_store.id}"])
      else
        @current_order = current_store.orders.create
      end
    else
      nil
    end
  end

I added skip_before_action :current_order to the following controllers: Customer, Dashboard, Product, Sessions, Stores, Welcome but the problem still seems to persist.

Ex: to get to a Store#show page, 3 "orders" are created.

Started GET "/21" for ::1 at 2016-08-25 16:10:48 +0800
Processing by StoresController#show as HTML
  Parameters: {"store_id"=>"21"}
  Store Load (0.1ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."slug" = ?  ORDER BY "stores"."id" ASC LIMIT 1  [["slug", "21"]]
  Store Load (0.1ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."id" = ? LIMIT 1  [["id", 21]]
  CACHE (0.0ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."slug" = ?  ORDER BY "stores"."id" ASC LIMIT 1  [["slug", "21"]]
  CACHE (0.0ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."id" = ? LIMIT 1  [["id", "21"]]
  Product Load (0.3ms)  SELECT "products".* FROM "products" WHERE "products"."store_id" = ?  [["store_id", 21]]
  Rendered stores/show.html.erb within layouts/customer (4.4ms)
  CACHE (0.0ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."slug" = ?  ORDER BY "stores"."id" ASC LIMIT 1  [["slug", "21"]]
  CACHE (0.0ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."id" = ? LIMIT 1  [["id", "21"]]
  CACHE (0.0ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."slug" = ?  ORDER BY "stores"."id" ASC LIMIT 1  [["slug", "21"]]
  CACHE (0.0ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."id" = ? LIMIT 1  [["id", "21"]]
  CACHE (0.0ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."slug" = ?  ORDER BY "stores"."id" ASC LIMIT 1  [["slug", "21"]]
  CACHE (0.0ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."id" = ? LIMIT 1  [["id", "21"]]
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" IS NULL LIMIT 1
  CACHE (0.0ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."slug" = ?  ORDER BY "stores"."id" ASC LIMIT 1  [["slug", "21"]]
  CACHE (0.0ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."id" = ? LIMIT 1  [["id", "21"]]
  CACHE (0.0ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."slug" = ?  ORDER BY "stores"."id" ASC LIMIT 1  [["slug", "21"]]
  CACHE (0.0ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."id" = ? LIMIT 1  [["id", "21"]]
  CACHE (0.0ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."slug" = ?  ORDER BY "stores"."id" ASC LIMIT 1  [["slug", "21"]]
  CACHE (0.0ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."id" = ? LIMIT 1  [["id", "21"]]
   (0.2ms)  begin transaction
  SQL (0.3ms)  INSERT INTO "orders" ("store_id", "created_at", "updated_at") VALUES (?, ?, ?)  [["store_id", 21], ["created_at", "2016-08-25 08:10:49.037060"], ["updated_at", "2016-08-25 08:10:49.037060"]]
   (7.6ms)  commit transaction
  Store Load (0.2ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."slug" = ?  ORDER BY "stores"."id" ASC LIMIT 1  [["slug", "21"]]
  Store Load (0.1ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."id" = ? LIMIT 1  [["id", 21]]
  CACHE (0.0ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."slug" = ?  ORDER BY "stores"."id" ASC LIMIT 1  [["slug", "21"]]
  CACHE (0.0ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."id" = ? LIMIT 1  [["id", "21"]]
  CACHE (0.0ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."slug" = ?  ORDER BY "stores"."id" ASC LIMIT 1  [["slug", "21"]]
  CACHE (0.0ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."id" = ? LIMIT 1  [["id", "21"]]
   (0.1ms)  begin transaction
  SQL (0.4ms)  INSERT INTO "orders" ("store_id", "created_at", "updated_at") VALUES (?, ?, ?)  [["store_id", 21], ["created_at", "2016-08-25 08:10:49.058540"], ["updated_at", "2016-08-25 08:10:49.058540"]]
   (1.1ms)  commit transaction
   (0.2ms)  SELECT SUM("order_lines"."quantity") FROM "order_lines" WHERE "order_lines"."order_id" = ?  [["order_id", 659]]
  Store Load (0.1ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."slug" = ?  ORDER BY "stores"."id" ASC LIMIT 1  [["slug", "21"]]
  Store Load (0.1ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."id" = ? LIMIT 1  [["id", 21]]
  CACHE (0.0ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."slug" = ?  ORDER BY "stores"."id" ASC LIMIT 1  [["slug", "21"]]
  CACHE (0.0ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."id" = ? LIMIT 1  [["id", "21"]]
  CACHE (0.0ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."slug" = ?  ORDER BY "stores"."id" ASC LIMIT 1  [["slug", "21"]]
  CACHE (0.0ms)  SELECT  "stores".* FROM "stores" WHERE "stores"."id" = ? LIMIT 1  [["id", "21"]]
   (0.1ms)  begin transaction
  SQL (0.4ms)  INSERT INTO "orders" ("store_id", "created_at", "updated_at") VALUES (?, ?, ?)  [["store_id", 21], ["created_at", "2016-08-25 08:10:49.070428"], ["updated_at", "2016-08-25 08:10:49.070428"]]
   (1.0ms)  commit transaction
  OrderLine Load (0.1ms)  SELECT "order_lines".* FROM "order_lines" WHERE "order_lines"."order_id" = ?  [["order_id", 660]]
  Rendered layouts/_cart_text.html.erb (23.8ms)
  Rendered layouts/_store_navigation.html.erb (50.2ms)
  Rendered layouts/_messages.html.erb (0.1ms)
Completed 200 OK in 206ms (Views: 186.9ms | ActiveRecord: 13.1ms)

Enable AJAX for Products added to Order

When User adds product to Order:

  1. Flash message "Item added to Cart"
  2. Update number of items in Cart Icon navbar
  3. Update total number of items in Order show view

When User deletes product (order line) from Order show view:

  1. flash message "Item removed from Cart"
  2. Remove item from Order show view without refresh
  3. Update number of items in Cart Icon navbar
  4. Update total number of items in Order show view

Charges Controller - issues

Charges#create method

Error --> Solution

  • unknown attribute 'charge' for Order (charges#create) ---> pass :charge_id, not :charge
  • charge_id always returning 0 ---> change type to string, not integer (Stripe returns a string)
  • AssociationTypeMismatch in @order = current_store.orders.build(order_params) ---> pass :customer_id, not :customer
  • customer's stripe_id always defaulting to 0 ----> change type to string, not integer (Stripe returns a string)

Create a User model

  • install the Devise gem
  • use Single Type Inheritance to indicate types of users: Admin, Owner, Customer
  • create relationships between Owners (has many products), Customers (has many orders)

eCommerce Features

Basic

Store

  • Display store products, store information
  • Guest customers can add products to cart, view cart, checkout cart, submit payment to Stripe
  • Save Guest Customer information to Guest Model
  • Update Order model with guest ID or customer ID and Stripe token (charge_id) Charges#create
  • Upon successful checkout, customer redirected to Order Confirmation page
  • Customers can create an account (sign up)
  • Upon Sign Up > log the Customer in to a session
  • Upon Sign Out > redirect to store_path
  • Customers can sign in and view order history (index of current_customer's orders)
  • For a signed-in Customer, checkout page will auto-populate existing customer information
  • Create a Membership model representing Customer has many Stores, Stores has many Customers
  • Save a new instance of Membership when a new Customer signs up in a single store

Root

  • Allow new user sign ups as Owners
  • Once a new Owner-user has signed up, can create store

Dashboard

  • Add two text fields to Store model (description, action_call)
  • Owner-user can edit Store information (About, Description) -- similar to storing product info
  • Allow Owner-user to select store if have multiple stores
  • Upon Owner-user log in > redirect to Dashboard Products#Index view
  • Owner-user can create, edit, and delete products
  • Owner-user can view Orders
  • Owner-user can view all Customer-users for a given store
  • Upon Owner-user log out > redirect to Welcome#Index view
  • Owner-user can upload product images (Carrierwave docs) and display images on Store show view, products index, products show

Check gems: Figaro, Carrierwave


Additional

Shipping

  • Allow Customer-user to input shipping address
  • Shipping model: shipping_address, status (shipped/not shipped), belongs_to Order
  • Store shipping address on the User table
  • Allow storing and selection of multiple addresses

Store

  • Show view reflects information based on Owner-User input
  • Navigation displays a User's gravatar if there is
  • Navigation bar should be responsive for smaller screens

Dashboard

  • Owner-user can email a Customer-user
  • Owner-user can update store view page (based on information in the Store model)
  • Owner-user can navigate between multiple stores

Create the Order model

Holds information for a collection of Order Lines

  • Customer ID
  • Date Paid
  • Completed (boolean)
  • Payment token (for Stripe) ** how to incorporate this? **
  • Total Paid

Orders belong_to Customers
Orders has_many Order Lines

Uninitialized Constant CarrierWave?

Attempting to get into Rspec, returned the following error:

/Users/Michelle/.rvm/gems/ruby-2.2.1/gems/carrierwave-0.11.2/lib/carrierwave.rb:14:in `configure': uninitialized constant CarrierWave::Uploader (NameError)

Store#New - Save Owner ID?

Store#New form takes a hidden_field for "owner_id", value of current_user.id
Returns error "Owner can't be blank"

Replacing 'hidden_field" as a "text_field" shows that it is accessing the current_user.id correctly, but it does not save the owner_id to the DB

Create the Order Views

Order Show view for Customer

  • contains a table for products, each row is an Order Line
  • Also include base customer information (name, address, phone number, email)
  • Update button --- update quantities of product (link to update Order Line?)
  • Delete button --- removes an Order Line (product)

Order Show view for Owner

  • IF order is completed, view should reflect date paid, amount paid

Order Index view for Customer

  • list of all orders for the current_user
  • Order number == a link to the Customer's Order show view
  • show "completed" status - a checkbox checked for yes, unchecked for no

Order Index view for Owner

  • a list of all orders for all customers
  • each Order should have an Order number, Customer Name, and completed status (checkbox)

Create a Product model

Attributes:

  • Product ID
  • Name
  • Description
  • Image
  • SKU
  • Count
  • Price

Optional attributes:

  • Type (if selling different types, but related, products)
  • Variants (e.g. multiple color choices of a single product)

Relationships:

  • Product has many Order Lines
  • Product belongs to an Owner

Guest Model

Guest Model should be separate from the Devise-Users (not a "Type" in the User model)

  • Order belongs_to GUEST (add guest_id to Order model)
  • Guest has_one Order (each instance of GUEST should be new, even if a repeated guest. Each guest will have one order at time of checkout)
  • Attributes: name, street address, city, state, zipcode, phone number, email
  • No password or email validations required

Implement Checkout on Order#Show

@mjthompsgb - Where would a "Checkout" link on the Order#Show view direct to? Would want to direct to a view that includes:

  • total price
  • customer information input/update fields (name, address, phone, email) depending on whether or not current_user has already signed in
  • Place to include credit card information (assuming this is related to Stripe integration)

I searched for Stripe/Rails integration and found the following resource on Stripe - (https://stripe.com/docs/checkout/rails). Will it be sufficient to follow their integration (including controllers and views) for my Checkout page?

Redirect upon sign out

if Owner-User sign out, redirect to root page

if Customer-User sign out, redirect to store#show page

Current_order not persisting?

When an item is added to cart, it appears that an order is not created.

In the navigation, a link and cart icon will only appear IF there is a current_order

<% if @current_order.present? %>
    <%= link_to store_order_path(@store.id, current_order.id), class: "btn btn-default" do  %>
        <span class="glyphicon glyphicon-shopping-cart"></span>
        <%= current_order.total_items %> Items
    <% end %>
 <% end %> 

After adding a product to cart, flash message "Product Added to Cart", but the link/icon do not appear.

Customer Log-In

Indicate that a customer is signing up for an account as part of the "ecommerce network"
store sign up pages - should indicate that the store is part of the branded network

Create a Order Line Model

Order Line model will hold all information associated with a Product that is placed into a "cart"

  • Product ID (associate with Product model)
  • Quantity
  • Price (Quantity x Product Price)

Order Line belongs_to a Product
Order Line belongs_to a Order

Create the Product Views

All Products view

  • products organized in a table grid
  • each square in the grid includes product image (thumbnail), product name (link to individual product page), price
  • Page should be responsive (number of items in the grid expands or contracts depending on the browser size)
  • Default should be 4 x 4 grid

Individual Product View

  • product image, name, description/specs, price
  • form field to indicate quantity of items
  • Add to Cart button == Create Order Line action
  • link to All Products view

New Product view

  • field inputs for product name, description, price, etc all product attributes
  • ability to upload product image

OrderLines#Create - Issues

  • undefined method “orders” on current_user.
  • Orders are associated with CUSTOMERS, not general users.
  • Need to check if current_user.customer? but this doesn’t include new users who are not yet customers
  • Or - update model for a current_user <> order association?

Image resources not loading

Images in app/assets/images/ do not load in the browser
Q: Related to Chrome ad-blocker?
A: turned off ad-blocker, but 404 response still exists

Dashboard Actions

Test:

  • product creation: save all attributes, make sure it belongs to a store and an owner
  • Order index page: list of orders
  • Order show page: show list of order_lines, customer information, order info (date placed), any shipping info?

Create the Order Controllers

Customers can:

  • Create -- a New order is created at the same time the current user creates the first order line in the current session
  • Read -- review the order in the Order checkout view

Owners can:

  • Delete -- delete an order
  • Update -- when an order is paid, should be marked complete (ideally this happens automatically once payment is processed)

Charges#Controller

  • Check if email already exists. If so, and email does not match the logged in current_customer redirect to user_sign_in, ELSE If not, checkout as Guest (save information to @guest)
  • In creating a new Stripe Charge, save either @customer_id or @guest_id as the customer value
  • Possible to save @customer_id or @guest_id in the new @order depending on what exists, require one, but not both

Create the Product Controllers

Only Owners and Admin have access to the following controllers:

  • Create - add new product
  • Update - update existing product information
  • Delete - can delete a product from store (should retain information

All Users have access to the Read controller

  • Read - show all products available

Create the Order Line Controllers

Customers can:

  • Create == Add to Cart button
  • Update == in the Order checkout view, update quantity
  • Delete == in the Order checkout view, delete an Order Line

Index -- returns all Order Lines for the current user

Redirect Owner-User sign In

When an Owner-User logs in, they should be redirected to the Dashboard Products#Index view (dashboard_store_products_path)

Need to find the Owner's store but current relationship is Store.owner, not Owner.store.

Currently Owner has_many Stores, Stores belong_to Owner, but should it be 1:1 relationship instead?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.