| @@ -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/ | |||||
| @@ -0,0 +1,3 @@ | |||||
| // Place all the styles related to the LineItems controller here. | |||||
| // They will automatically be included in application.css. | |||||
| // You can use Sass (SCSS) here: http://sass-lang.com/ | |||||
| @@ -0,0 +1,74 @@ | |||||
| class LineItemsController < ApplicationController | |||||
| before_action :set_line_item, only: [:show, :edit, :update, :destroy] | |||||
| # GET /line_items | |||||
| # GET /line_items.json | |||||
| def index | |||||
| @line_items = LineItem.all | |||||
| end | |||||
| # GET /line_items/1 | |||||
| # GET /line_items/1.json | |||||
| def show | |||||
| end | |||||
| # GET /line_items/new | |||||
| def new | |||||
| @line_item = LineItem.new | |||||
| end | |||||
| # GET /line_items/1/edit | |||||
| def edit | |||||
| end | |||||
| # POST /line_items | |||||
| # POST /line_items.json | |||||
| def create | |||||
| @line_item = LineItem.new(line_item_params) | |||||
| respond_to do |format| | |||||
| if @line_item.save | |||||
| format.html { redirect_to @line_item, notice: 'Line item was successfully created.' } | |||||
| format.json { render :show, status: :created, location: @line_item } | |||||
| else | |||||
| format.html { render :new } | |||||
| format.json { render json: @line_item.errors, status: :unprocessable_entity } | |||||
| end | |||||
| end | |||||
| end | |||||
| # PATCH/PUT /line_items/1 | |||||
| # PATCH/PUT /line_items/1.json | |||||
| def update | |||||
| respond_to do |format| | |||||
| if @line_item.update(line_item_params) | |||||
| format.html { redirect_to @line_item, notice: 'Line item was successfully updated.' } | |||||
| format.json { render :show, status: :ok, location: @line_item } | |||||
| else | |||||
| format.html { render :edit } | |||||
| format.json { render json: @line_item.errors, status: :unprocessable_entity } | |||||
| end | |||||
| end | |||||
| end | |||||
| # DELETE /line_items/1 | |||||
| # DELETE /line_items/1.json | |||||
| def destroy | |||||
| @line_item.destroy | |||||
| respond_to do |format| | |||||
| format.html { redirect_to line_items_url, notice: 'Line item was successfully destroyed.' } | |||||
| format.json { head :no_content } | |||||
| end | |||||
| end | |||||
| private | |||||
| # Use callbacks to share common setup or constraints between actions. | |||||
| def set_line_item | |||||
| @line_item = LineItem.find(params[:id]) | |||||
| end | |||||
| # Never trust parameters from the scary internet, only allow the white list through. | |||||
| def line_item_params | |||||
| params.require(:line_item).permit(:product_id, :cart_id) | |||||
| end | |||||
| end | |||||
| @@ -0,0 +1,2 @@ | |||||
| module LineItemsHelper | |||||
| end | |||||
| @@ -1,2 +1,3 @@ | |||||
| class Cart < ApplicationRecord | class Cart < ApplicationRecord | ||||
| has_many :line_items, dependent: :destroy | |||||
| end | end | ||||
| @@ -0,0 +1,4 @@ | |||||
| class LineItem < ApplicationRecord | |||||
| belongs_to :product | |||||
| belongs_to :cart | |||||
| end | |||||
| @@ -1,4 +1,8 @@ | |||||
| class Product < ApplicationRecord | class Product < ApplicationRecord | ||||
| has_many :line_items | |||||
| before_destroy :ensure_not_referenced_by_any_line_item | |||||
| validates :title, :description, :image_url, :price, presence: true | validates :title, :description, :image_url, :price, presence: true | ||||
| validates :price, numericality: {greater_than_or_equal_to: 0.01} | validates :price, numericality: {greater_than_or_equal_to: 0.01} | ||||
| validates :title, uniqueness: true, length: { minimum: 5, maximum: 30 } | validates :title, uniqueness: true, length: { minimum: 5, maximum: 30 } | ||||
| @@ -6,4 +10,12 @@ class Product < ApplicationRecord | |||||
| with: %r{\.(gif|jpg|png)\Z}i, | with: %r{\.(gif|jpg|png)\Z}i, | ||||
| message: 'must be URL for GIF, JPG or PNG image.' | message: 'must be URL for GIF, JPG or PNG image.' | ||||
| } | } | ||||
| private | |||||
| def ensure_not_referenced_by_any_line_item | |||||
| unless line_items.empty? | |||||
| errors.add(:base, 'Line Items present') | |||||
| throw :abort | |||||
| end | |||||
| end | |||||
| end | end | ||||
| @@ -0,0 +1,27 @@ | |||||
| <%= form_for(line_item) do |f| %> | |||||
| <% if line_item.errors.any? %> | |||||
| <div id="error_explanation"> | |||||
| <h2><%= pluralize(line_item.errors.count, "error") %> prohibited this line_item from being saved:</h2> | |||||
| <ul> | |||||
| <% line_item.errors.full_messages.each do |message| %> | |||||
| <li><%= message %></li> | |||||
| <% end %> | |||||
| </ul> | |||||
| </div> | |||||
| <% end %> | |||||
| <div class="field"> | |||||
| <%= f.label :product_id %> | |||||
| <%= f.text_field :product_id %> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <%= f.label :cart_id %> | |||||
| <%= f.text_field :cart_id %> | |||||
| </div> | |||||
| <div class="actions"> | |||||
| <%= f.submit %> | |||||
| </div> | |||||
| <% end %> | |||||
| @@ -0,0 +1,2 @@ | |||||
| json.extract! line_item, :id, :product_id, :cart_id, :created_at, :updated_at | |||||
| json.url line_item_url(line_item, format: :json) | |||||
| @@ -0,0 +1,6 @@ | |||||
| <h1>Editing Line Item</h1> | |||||
| <%= render 'form', line_item: @line_item %> | |||||
| <%= link_to 'Show', @line_item %> | | |||||
| <%= link_to 'Back', line_items_path %> | |||||
| @@ -0,0 +1,29 @@ | |||||
| <p id="notice"><%= notice %></p> | |||||
| <h1>Line Items</h1> | |||||
| <table> | |||||
| <thead> | |||||
| <tr> | |||||
| <th>Product</th> | |||||
| <th>Cart</th> | |||||
| <th colspan="3"></th> | |||||
| </tr> | |||||
| </thead> | |||||
| <tbody> | |||||
| <% @line_items.each do |line_item| %> | |||||
| <tr> | |||||
| <td><%= line_item.product %></td> | |||||
| <td><%= line_item.cart %></td> | |||||
| <td><%= link_to 'Show', line_item %></td> | |||||
| <td><%= link_to 'Edit', edit_line_item_path(line_item) %></td> | |||||
| <td><%= link_to 'Destroy', line_item, method: :delete, data: { confirm: 'Are you sure?' } %></td> | |||||
| </tr> | |||||
| <% end %> | |||||
| </tbody> | |||||
| </table> | |||||
| <br> | |||||
| <%= link_to 'New Line Item', new_line_item_path %> | |||||
| @@ -0,0 +1 @@ | |||||
| json.array! @line_items, partial: 'line_items/line_item', as: :line_item | |||||
| @@ -0,0 +1,5 @@ | |||||
| <h1>New Line Item</h1> | |||||
| <%= render 'form', line_item: @line_item %> | |||||
| <%= link_to 'Back', line_items_path %> | |||||
| @@ -0,0 +1,14 @@ | |||||
| <p id="notice"><%= notice %></p> | |||||
| <p> | |||||
| <strong>Product:</strong> | |||||
| <%= @line_item.product %> | |||||
| </p> | |||||
| <p> | |||||
| <strong>Cart:</strong> | |||||
| <%= @line_item.cart %> | |||||
| </p> | |||||
| <%= link_to 'Edit', edit_line_item_path(@line_item) %> | | |||||
| <%= link_to 'Back', line_items_path %> | |||||
| @@ -0,0 +1 @@ | |||||
| json.partial! "line_items/line_item", line_item: @line_item | |||||
| @@ -1,4 +1,5 @@ | |||||
| Rails.application.routes.draw do | Rails.application.routes.draw do | ||||
| resources :line_items | |||||
| resources :carts | resources :carts | ||||
| root 'store#index', as: 'store_index' | root 'store#index', as: 'store_index' | ||||
| @@ -0,0 +1,10 @@ | |||||
| class CreateLineItems < ActiveRecord::Migration[5.0] | |||||
| def change | |||||
| create_table :line_items do |t| | |||||
| t.references :product, foreign_key: true | |||||
| t.belongs_to :cart, foreign_key: true | |||||
| t.timestamps | |||||
| end | |||||
| end | |||||
| end | |||||
| @@ -10,13 +10,22 @@ | |||||
| # | # | ||||
| # 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: 20161115210150) do | |||||
| ActiveRecord::Schema.define(version: 20161115211138) 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 | ||||
| t.datetime "updated_at", null: false | t.datetime "updated_at", null: false | ||||
| end | end | ||||
| create_table "line_items", force: :cascade do |t| | |||||
| t.integer "product_id" | |||||
| t.integer "cart_id" | |||||
| t.datetime "created_at", null: false | |||||
| t.datetime "updated_at", null: false | |||||
| t.index ["cart_id"], name: "index_line_items_on_cart_id" | |||||
| t.index ["product_id"], name: "index_line_items_on_product_id" | |||||
| 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,48 @@ | |||||
| require 'test_helper' | |||||
| class LineItemsControllerTest < ActionDispatch::IntegrationTest | |||||
| setup do | |||||
| @line_item = line_items(:one) | |||||
| end | |||||
| test "should get index" do | |||||
| get line_items_url | |||||
| assert_response :success | |||||
| end | |||||
| test "should get new" do | |||||
| get new_line_item_url | |||||
| assert_response :success | |||||
| end | |||||
| test "should create line_item" do | |||||
| assert_difference('LineItem.count') do | |||||
| post line_items_url, params: { line_item: { cart_id: @line_item.cart_id, product_id: @line_item.product_id } } | |||||
| end | |||||
| assert_redirected_to line_item_url(LineItem.last) | |||||
| end | |||||
| test "should show line_item" do | |||||
| get line_item_url(@line_item) | |||||
| assert_response :success | |||||
| end | |||||
| test "should get edit" do | |||||
| get edit_line_item_url(@line_item) | |||||
| assert_response :success | |||||
| end | |||||
| test "should update line_item" do | |||||
| patch line_item_url(@line_item), params: { line_item: { cart_id: @line_item.cart_id, product_id: @line_item.product_id } } | |||||
| assert_redirected_to line_item_url(@line_item) | |||||
| end | |||||
| test "should destroy line_item" do | |||||
| assert_difference('LineItem.count', -1) do | |||||
| delete line_item_url(@line_item) | |||||
| end | |||||
| assert_redirected_to line_items_url | |||||
| end | |||||
| end | |||||
| @@ -44,6 +44,14 @@ class ProductsControllerTest < ActionDispatch::IntegrationTest | |||||
| assert_redirected_to product_url(@product) | assert_redirected_to product_url(@product) | ||||
| end | end | ||||
| test "can't delete product in cart" do | |||||
| assert_difference('Product.count', 0) do | |||||
| delete product_url(products(:two)) | |||||
| end | |||||
| assert_redirected_to products_url | |||||
| end | |||||
| test "should destroy product" do | test "should destroy product" do | ||||
| assert_difference('Product.count', -1) do | assert_difference('Product.count', -1) do | ||||
| delete product_url(@product) | delete product_url(@product) | ||||
| @@ -51,4 +59,7 @@ class ProductsControllerTest < ActionDispatch::IntegrationTest | |||||
| assert_redirected_to products_url | assert_redirected_to products_url | ||||
| end | end | ||||
| end | end | ||||
| @@ -0,0 +1,10 @@ | |||||
| # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html | |||||
| # TODO: Warum hat das hier nicht funktioniert wenn das beides in einem eigenen Cart lag? | |||||
| one: | |||||
| product: two | |||||
| cart: one | |||||
| two: | |||||
| product: two | |||||
| cart: two | |||||
| @@ -0,0 +1,7 @@ | |||||
| require 'test_helper' | |||||
| class LineItemTest < ActiveSupport::TestCase | |||||
| # test "the truth" do | |||||
| # assert true | |||||
| # end | |||||
| end | |||||