| @@ -0,0 +1,3 @@ | |||||
| # Place all the behaviors and hooks related to the matching controller here. | |||||
| # All this logic will automatically be available in application.js. | |||||
| # You can use CoffeeScript in this file: http://coffeescript.org/ | |||||
| @@ -109,3 +109,43 @@ | |||||
| display: none; | display: none; | ||||
| } | } | ||||
| } | } | ||||
| .depot_form { | |||||
| fieldset { | |||||
| background: #efe; | |||||
| legend { | |||||
| color: #dfd; | |||||
| background: #141; | |||||
| font-family: sans-serif; | |||||
| padding: 0.2em 1em; | |||||
| } | |||||
| div { | |||||
| margin-bottom: 0.3em; | |||||
| } | |||||
| } | |||||
| form { | |||||
| label { | |||||
| width: 5em; | |||||
| float: left; | |||||
| text-align: right; | |||||
| padding-top: 0.2em; | |||||
| margin-right: 0.1em; | |||||
| display: block; | |||||
| } | |||||
| select, textarea, input { | |||||
| margin-left: 0.5em; | |||||
| } | |||||
| .submit { | |||||
| margin-left: 4em; | |||||
| } | |||||
| br { | |||||
| display: none | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,3 @@ | |||||
| // Place all the styles related to the Orders controller here. | |||||
| // They will automatically be included in application.css. | |||||
| // You can use Sass (SCSS) here: http://sass-lang.com/ | |||||
| @@ -0,0 +1,87 @@ | |||||
| class OrdersController < ApplicationController | |||||
| include CurrentCart | |||||
| before_action :set_cart, only: [:new, :create] | |||||
| before_action :ensure_cart_isnt_empty, only: :new | |||||
| before_action :set_order, only: [:show, :edit, :update, :destroy] | |||||
| # GET /orders | |||||
| # GET /orders.json | |||||
| def index | |||||
| @orders = Order.all | |||||
| end | |||||
| # GET /orders/1 | |||||
| # GET /orders/1.json | |||||
| def show | |||||
| end | |||||
| # GET /orders/new | |||||
| def new | |||||
| @order = Order.new | |||||
| end | |||||
| # GET /orders/1/edit | |||||
| def edit | |||||
| end | |||||
| # POST /orders | |||||
| # POST /orders.json | |||||
| def create | |||||
| @order = Order.new(order_params) | |||||
| @order.add_line_items_from_cart(@cart) | |||||
| respond_to do |format| | |||||
| if @order.save | |||||
| Cart.destroy(session[:cart_id]) | |||||
| session[:cart_id] = nil | |||||
| format.html { redirect_to store_index_url, notice: 'Thank you for your order.' } | |||||
| format.json { render :show, status: :created, location: @order } | |||||
| else | |||||
| format.html { render :new } | |||||
| format.json { render json: @order.errors, status: :unprocessable_entity } | |||||
| end | |||||
| end | |||||
| end | |||||
| # PATCH/PUT /orders/1 | |||||
| # PATCH/PUT /orders/1.json | |||||
| def update | |||||
| respond_to do |format| | |||||
| if @order.update(order_params) | |||||
| format.html { redirect_to @order, notice: 'Order was successfully updated.' } | |||||
| format.json { render :show, status: :ok, location: @order } | |||||
| else | |||||
| format.html { render :edit } | |||||
| format.json { render json: @order.errors, status: :unprocessable_entity } | |||||
| end | |||||
| end | |||||
| end | |||||
| # DELETE /orders/1 | |||||
| # DELETE /orders/1.json | |||||
| def destroy | |||||
| @order.destroy | |||||
| respond_to do |format| | |||||
| format.html { redirect_to orders_url, notice: 'Order was successfully destroyed.' } | |||||
| format.json { head :no_content } | |||||
| end | |||||
| end | |||||
| private | |||||
| # Use callbacks to share common setup or constraints between actions. | |||||
| def set_order | |||||
| @order = Order.find(params[:id]) | |||||
| end | |||||
| # Never trust parameters from the scary internet, only allow the white list through. | |||||
| def order_params | |||||
| params.require(:order).permit(:name, :address, :email, :pay_type) | |||||
| end | |||||
| def ensure_cart_isnt_empty | |||||
| if @cart.line_items.empty? | |||||
| redirect_to store_index_url, notice: 'Your cart is empty' | |||||
| end | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,2 @@ | |||||
| module OrdersHelper | |||||
| end | |||||
| @@ -1,5 +1,6 @@ | |||||
| class LineItem < ApplicationRecord | class LineItem < ApplicationRecord | ||||
| belongs_to :product | |||||
| belongs_to :order, optional: true | |||||
| belongs_to :product, optional: true | |||||
| belongs_to :cart | belongs_to :cart | ||||
| def total_price | def total_price | ||||
| @@ -0,0 +1,17 @@ | |||||
| class Order < ApplicationRecord | |||||
| has_many :line_items, dependent: :destroy | |||||
| enum pay_type: { | |||||
| "Check" => 0, | |||||
| "Credit card" => 1, | |||||
| "Purchase order" => 2 | |||||
| } | |||||
| validates :name, :address, :email, :pay_type, presence: true | |||||
| validates :pay_type, inclusion: pay_types.keys | |||||
| def add_line_items_from_cart(cart) | |||||
| cart.line_items.each do |item| | |||||
| item.cart_id = nil | |||||
| line_items << item | |||||
| end | |||||
| end | |||||
| end | |||||
| @@ -10,4 +10,5 @@ | |||||
| </table> | </table> | ||||
| <%= button_to 'Checkout', new_order_path, method: :get %> | |||||
| <%= button_to 'Empty Cart', cart, method: :delete, data: { confirm: 'Are you sure?'} %> | <%= button_to 'Empty Cart', cart, method: :delete, data: { confirm: 'Are you sure?'} %> | ||||
| @@ -1,3 +1,5 @@ | |||||
| $('#notice').hide(); | |||||
| if ($('#cart tr').length == 1) { $('#cart').show('blind', 1000); } | if ($('#cart tr').length == 1) { $('#cart').show('blind', 1000); } | ||||
| $('#cart').html("<%=j render(@cart) %>") | $('#cart').html("<%=j render(@cart) %>") | ||||
| @@ -0,0 +1,37 @@ | |||||
| <%= form_for(order) do |f| %> | |||||
| <% if order.errors.any? %> | |||||
| <div id="error_explanation"> | |||||
| <h2><%= pluralize(order.errors.count, "error") %> prohibited this order from being saved:</h2> | |||||
| <ul> | |||||
| <% order.errors.full_messages.each do |message| %> | |||||
| <li><%= message %></li> | |||||
| <% end %> | |||||
| </ul> | |||||
| </div> | |||||
| <% end %> | |||||
| <div class="field"> | |||||
| <%= f.label :name %> | |||||
| <%= f.text_field :name, size: 40 %> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <%= f.label :address %> | |||||
| <%= f.text_area :address, rows: 3, cols: 40 %> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <%= f.label :email %> | |||||
| <%= f.email_field :email, size: 40 %> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <%= f.label :pay_type %> | |||||
| <%= f.select :pay_type, Order.pay_types.keys, prompt: 'Select a payment method' %> | |||||
| </div> | |||||
| <div class="actions"> | |||||
| <%= f.submit 'Place order' %> | |||||
| </div> | |||||
| <% end %> | |||||
| @@ -0,0 +1,2 @@ | |||||
| json.extract! order, :id, :name, :address, :email, :pay_type, :created_at, :updated_at | |||||
| json.url order_url(order, format: :json) | |||||
| @@ -0,0 +1,6 @@ | |||||
| <h1>Editing Order</h1> | |||||
| <%= render 'form', order: @order %> | |||||
| <%= link_to 'Show', @order %> | | |||||
| <%= link_to 'Back', orders_path %> | |||||
| @@ -0,0 +1,33 @@ | |||||
| <p id="notice"><%= notice %></p> | |||||
| <h1>Orders</h1> | |||||
| <table> | |||||
| <thead> | |||||
| <tr> | |||||
| <th>Name</th> | |||||
| <th>Address</th> | |||||
| <th>Email</th> | |||||
| <th>Pay type</th> | |||||
| <th colspan="3"></th> | |||||
| </tr> | |||||
| </thead> | |||||
| <tbody> | |||||
| <% @orders.each do |order| %> | |||||
| <tr> | |||||
| <td><%= order.name %></td> | |||||
| <td><%= order.address %></td> | |||||
| <td><%= order.email %></td> | |||||
| <td><%= order.pay_type %></td> | |||||
| <td><%= link_to 'Show', order %></td> | |||||
| <td><%= link_to 'Edit', edit_order_path(order) %></td> | |||||
| <td><%= link_to 'Destroy', order, method: :delete, data: { confirm: 'Are you sure?' } %></td> | |||||
| </tr> | |||||
| <% end %> | |||||
| </tbody> | |||||
| </table> | |||||
| <br> | |||||
| <%= link_to 'New Order', new_order_path %> | |||||
| @@ -0,0 +1 @@ | |||||
| json.array! @orders, partial: 'orders/order', as: :order | |||||
| @@ -0,0 +1,6 @@ | |||||
| <div class="depot_form"> | |||||
| <fieldset> | |||||
| <legend>Please Enter Your Details</legend> | |||||
| <%= render 'form', order: @order %> | |||||
| </fieldset> | |||||
| </div> | |||||
| @@ -0,0 +1,24 @@ | |||||
| <p id="notice"><%= notice %></p> | |||||
| <p> | |||||
| <strong>Name:</strong> | |||||
| <%= @order.name %> | |||||
| </p> | |||||
| <p> | |||||
| <strong>Address:</strong> | |||||
| <%= @order.address %> | |||||
| </p> | |||||
| <p> | |||||
| <strong>Email:</strong> | |||||
| <%= @order.email %> | |||||
| </p> | |||||
| <p> | |||||
| <strong>Pay type:</strong> | |||||
| <%= @order.pay_type %> | |||||
| </p> | |||||
| <%= link_to 'Edit', edit_order_path(@order) %> | | |||||
| <%= link_to 'Back', orders_path %> | |||||
| @@ -0,0 +1 @@ | |||||
| json.partial! "orders/order", order: @order | |||||
| @@ -1,4 +1,5 @@ | |||||
| Rails.application.routes.draw do | Rails.application.routes.draw do | ||||
| resources :orders | |||||
| resources :line_items | resources :line_items | ||||
| resources :carts | resources :carts | ||||
| root 'store#index', as: 'store_index' | root 'store#index', as: 'store_index' | ||||
| @@ -0,0 +1,12 @@ | |||||
| class CreateOrders < ActiveRecord::Migration[5.0] | |||||
| def change | |||||
| create_table :orders do |t| | |||||
| t.string :name | |||||
| t.text :address | |||||
| t.string :email | |||||
| t.integer :pay_type | |||||
| t.timestamps | |||||
| end | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,5 @@ | |||||
| class AddOrderToLineItem < ActiveRecord::Migration[5.0] | |||||
| def change | |||||
| add_reference :line_items, :order, foreign_key: true | |||||
| end | |||||
| end | |||||
| @@ -10,7 +10,7 @@ | |||||
| # | # | ||||
| # It's strongly recommended that you check this file into your version control system. | # It's strongly recommended that you check this file into your version control system. | ||||
| ActiveRecord::Schema.define(version: 20161116091835) do | |||||
| ActiveRecord::Schema.define(version: 20161116161423) do | |||||
| create_table "carts", force: :cascade do |t| | create_table "carts", force: :cascade do |t| | ||||
| t.datetime "created_at", null: false | t.datetime "created_at", null: false | ||||
| @@ -23,10 +23,21 @@ ActiveRecord::Schema.define(version: 20161116091835) do | |||||
| t.datetime "created_at", null: false | t.datetime "created_at", null: false | ||||
| t.datetime "updated_at", null: false | t.datetime "updated_at", null: false | ||||
| t.integer "quantity", default: 1 | t.integer "quantity", default: 1 | ||||
| t.integer "order_id" | |||||
| t.index ["cart_id"], name: "index_line_items_on_cart_id" | t.index ["cart_id"], name: "index_line_items_on_cart_id" | ||||
| t.index ["order_id"], name: "index_line_items_on_order_id" | |||||
| t.index ["product_id"], name: "index_line_items_on_product_id" | t.index ["product_id"], name: "index_line_items_on_product_id" | ||||
| end | end | ||||
| create_table "orders", force: :cascade do |t| | |||||
| t.string "name" | |||||
| t.text "address" | |||||
| t.string "email" | |||||
| t.integer "pay_type" | |||||
| t.datetime "created_at", null: false | |||||
| t.datetime "updated_at", null: false | |||||
| end | |||||
| create_table "products", force: :cascade do |t| | create_table "products", force: :cascade do |t| | ||||
| t.string "title" | t.string "title" | ||||
| t.text "description" | t.text "description" | ||||
| @@ -0,0 +1,56 @@ | |||||
| require 'test_helper' | |||||
| class OrdersControllerTest < ActionDispatch::IntegrationTest | |||||
| setup do | |||||
| @order = orders(:one) | |||||
| end | |||||
| test "should get index" do | |||||
| get orders_url | |||||
| assert_response :success | |||||
| end | |||||
| test "requires item in cart" do | |||||
| get new_order_url | |||||
| assert_redirected_to store_index_url | |||||
| assert_equal flash[:notice], 'Your cart is empty' | |||||
| end | |||||
| test "should get new" do | |||||
| post line_items_url, params: { product_id: products(:ruby).id } | |||||
| get new_order_url | |||||
| assert_response :success | |||||
| end | |||||
| test "should create order" do | |||||
| assert_difference('Order.count') do | |||||
| post orders_url, params: { order: { address: @order.address, email: @order.email, name: @order.name, pay_type: @order.pay_type } } | |||||
| end | |||||
| assert_redirected_to store_index_url | |||||
| end | |||||
| test "should show order" do | |||||
| get order_url(@order) | |||||
| assert_response :success | |||||
| end | |||||
| test "should get edit" do | |||||
| get edit_order_url(@order) | |||||
| assert_response :success | |||||
| end | |||||
| test "should update order" do | |||||
| patch order_url(@order), params: { order: { address: @order.address, email: @order.email, name: @order.name, pay_type: @order.pay_type } } | |||||
| assert_redirected_to order_url(@order) | |||||
| end | |||||
| test "should destroy order" do | |||||
| assert_difference('Order.count', -1) do | |||||
| delete order_url(@order) | |||||
| end | |||||
| assert_redirected_to orders_url | |||||
| end | |||||
| end | |||||
| @@ -6,5 +6,5 @@ one: | |||||
| cart: one | cart: one | ||||
| two: | two: | ||||
| product: two | |||||
| cart: two | |||||
| product: ruby | |||||
| order: one | |||||
| @@ -0,0 +1,13 @@ | |||||
| # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html | |||||
| one: | |||||
| name: Dave Thomas | |||||
| address: MyText | |||||
| email: dave@example.org | |||||
| pay_type: Check | |||||
| two: | |||||
| name: MyString | |||||
| address: MyText | |||||
| email: MyString | |||||
| pay_type: 1 | |||||
| @@ -0,0 +1,7 @@ | |||||
| require 'test_helper' | |||||
| class OrderTest < ActiveSupport::TestCase | |||||
| # test "the truth" do | |||||
| # assert true | |||||
| # end | |||||
| end | |||||