[RUBY] Create an EC site with Rails 5 ⑨ ~ Create a cart function ~

Introduction

This is a continuation of the series "Creating an EC site with Rails 5 ⑧" (https://qiita.com/GreenFingers_tk/items/0d2caea916a82e234af2), which creates an EC site where you can shop at a fictitious bakery. This time we will make a cart function. The appearance of the EC site is finally ready.

Source code

https://github.com/Sn16799/bakeryFUMIZUKI

Model association

fumizuki_ER.jpg

The models related to the cart function are mainly Customer and Product. There is no such thing as the main body of the cart in the cart function, and when you select a product and press the "Add to cart" button, one data item is registered for each product. The CartItem model acts as an intermediate table that stores only the Customer and Product IDs and the number of products.

Controller

app/controllers/cart_items_controller.rb


class CartItemsController < ApplicationController

  before_action :authenticate_customer!
  before_action :set_cart_item, only: [:show, :update, :destroy, :edit]
  before_action :set_customer

  def create
    @cart_item = current_customer.cart_items.build(cart_item_params)
    @current_item = CartItem.find_by(product_id: @cart_item.product_id,customer_id: @cart_item.customer_id)
    #If there is no same product in the cart, add a new one, if there is, add it to the existing data
    if @current_item.nil?
      if @cart_item.save
        flash[:success] = 'The item has been added to the cart!'
        redirect_to cart_items_path
      else
        @carts_items = @customer.cart_items.all
        render 'index'
        flash[:danger] = 'The item could not be added to the cart.'
      end
    else
      @current_item.quantity += params[:quantity].to_i
      @current_item.update(cart_item_params)
      redirect_to cart_items_path
    end
  end

  def destroy
    @cart_item.destroy
    redirect_to cart_items_path
    flash[:info] = 'I canceled the item in the cart.'
  end

  def index
    @cart_items = @customer.cart_items.all
  end

  def update
    if @cart_item.update(cart_item_params)
      redirect_to cart_items_path
      flash[:success] = 'The items in the cart have been updated!'
    end
  end

  def destroy_all #Erase all items in the cart
    @customer.cart_items.destroy_all
    redirect_to cart_items_path
    flash[:info] = 'I emptied my cart.'
  end

  private

  def set_customer
    @customer = current_customer
  end

  def set_cart_item
    @cart_item = CartItem.find(params[:id])
  end

  def cart_item_params
    params.require(:cart_item).permit(:product_id, :customer_id, :quantity)
  end
end

If you just write save in the create action, when you try to buy the same product, the same product will be registered as different data, such as ** "Pain de mie 1, Pain de mie 2, Pain de mie 1, ..." **. This happens due to the structure of the table, but since it is convenient to be able to display the additional items added to the cart later, the if statement separates the processing.

Also, when I wanted to be able to cancel the items in the cart individually and empty the contents of the cart all at once, it is convenient as destroy_all. I found a method.

View

index screen

html:app/views/cart_items/index.html.erb


<div class="col-lg-10 offset-lg-1 space">
  <div class="container-fluid">
    <!--title+Erase all method-->
    <div class="row">
      <div class="col-lg-4">
        <h2>
          <span style="display: inline-block;">shopping</span>
          <span style="display: inline-block;">cart</span>
        </h2>
      </div>
      <div class="col-lg-4">
        <%= link_to 'Empty the cart', destroy_all_cart_items_path, method: :delete, class: 'btn btn-danger' %>
      </div>
    </div>

    <!--List of products in the cart-->
    <div class="d-none d-lg-block">
      <div class="row space">
        <div class="col-lg-5"><h4>Product name</h4></div>
        <div class="col-lg-2"><h4>Unit price (tax included)</h4></div>
        <div class="col-lg-2"><h4>quantity</h4></div>
        <div class="col-lg-2"><h4>subtotal</h4></div>
      </div>
    </div>

    <% sum_all = 0 %>
    <% @cart_items.each do |cart_item| %>
    <div class="row space-sm">
      <div class="col-lg-3">
        <%= link_to product_path(cart_item.product) do %>
        <%= attachment_image_tag(cart_item.product, :image, :fill, 100, 100, fallback: "no_img.jpg ") %>
        <% end %>
      </div>
      <div class="col-lg-2">
        <%= link_to product_path(cart_item.product) do %>
        <%= cart_item.product.name %>
        <% end %>
      </div>
      <div class="col-lg-2">
        <%= price_include_tax(cart_item.product.price) %>
      </div>
      <div class="col-lg-2">
        <%= form_with model: cart_item, local: true do |f| %>
        <%= f.number_field :quantity, value: cart_item.quantity, min:1, max:99  %>
        <%= f.submit "Change", class: "btn btn-primary" %>
        <% end %>
      </div>
      <div class="col-lg-2">
        <%= sum_product = price_include_tax(cart_item.product.price).to_i * cart_item.quantity %>Circle
        <% sum_all += sum_product %>
      </div>
      <div class="col-lg-1">
        <%= link_to "delete", cart_item_path(cart_item), method: :delete, class: "btn btn-danger"%>
      </div>
    </div>
    <% end %>

    <!--total fee+Information input-->
    <div class="row space">
      <div class="col-lg-2 offset-lg-7 space-sm">
        <%= link_to "Continue shopping", customer_top_path, class: "btn btn-danger "%>
      </div>
      <div class="col-lg-3 space-sm">
        <div class="row">
          <h4>total fee:<%= sum_all %>Circle</h4>
        </div>
      </div>
    </div>
    <div class="row space">
      <div class="col-lg-3 offset-lg-9">
        <%= link_to "Proceed to information input", new_order_path, class: "btn btn-danger btn-lg" %>
      </div>
    </div>

  </div>
</div>

The subtotal for each product and the total for all products are displayed by incorporating a calculation formula in the each statement on the view. In general, it seems that it is not desirable to perform detailed calculations and branch processing in view, so is there any other good method?

app/helpers/application_helper.rb


def price_include_tax(price)
  price = price * 1.08
  "#{price.floor}Circle"
end

This is the helper used to display the tax-included price of the product in the above HTML. The part after the decimal point is truncated by floor. For more information on decimal point processing, see here.

app/assets/stylesheets/application.scss


.space-sm {
  padding-top: 20px;
}

Postscript

The implementation of features has become a bit more complicated, and it's finally getting interesting. Even if you look inside the site, you can feel like shopping by adding products to the cart. After that, if you create around Order (order information), the customer site is completed!

However, in this series, the admin site is also created by myself, so the amount of code is about half. However, the function of the Order model was extremely difficult to experience when I made it last time, so if I could do that, I would be able to do something about it.

Now, can I explain the most difficult Order model in an easy-to-understand manner? Continue to next time!

reference

Pikawaka [Ruby] Round, round up, and round down by specifying the number of digits after the decimal point!

Recommended Posts

Create an EC site with Rails 5 ⑨ ~ Create a cart function ~
Create an EC site with Rails 5 ⑩ ~ Create an order function ~
[Rails] EC site cart function
Create an EC site with Rails5 ⑤ ~ Customer model ~
Create an EC site with Rails5 ⑦ ~ Address, Genre model ~
Create an EC site with Rails5 ④ ~ Header and footer ~
Create an EC site with Rails5 ⑥ ~ seed data input ~
[Rails withdrawal] Create a simple withdrawal function with rails
Create an EC site with Rails5 ② ~ Bootstrap4 settings, Controller / action definition ~
Create an EC site with Rails5 ③-Set model associations and other things-
Create pagination function with Rails Kaminari
[Rails] Create an email sending function with ActionMailer (complete version)
[Rails] Create an evaluation function using raty.js
[Rails6] Create a new app with Rails [Beginner]
Make a login function with Rails anyway
[Rails 5] Create a new app with Rails [Beginner]
Make a site template easily with Rails
Create an or search function with Ransack.
Create a SPA with authentication function with Rails API mode + devise_token_auth + Vue.js 3 (Rails edition)
Create an EC site using stripe! (Account creation)
Create a team chat with Rails Action Cable
Let's make a search function with Rails (ransack)
[Rails] Create an application
Create a user with an empty password on CentOS7
Create a Service with an empty model Liferay 7.0 / DXP
Create a simple demo site with Spring Security with Spring Boot 2.1
I tried to create a shopping site administrator function / screen with Java and Spring
Creating an EC site with Rails5 ①-App configuration, various gem preparation, Model / Routing creation-
Introduced graph function with rails
Create a playground with Xcode 12
Login function implementation with rails
Create a name input function
Tutorial to create a blog with Rails for beginners Part 1
[Rails] I tried to create a mini app with FullCalendar
[Rails DM] Let's create a notification function when DM is sent!
A series of steps to create portfolio deliverables with Rails
Tutorial to create a blog with Rails for beginners Part 2
Tutorial to create a blog with Rails for beginners Part 0
A new employee tried to create an authentication / authorization function from scratch with Spring Security
Create an immutable class with JAVA
Create a Vue3 environment with Docker!
Create portfolio with rails + postgres sql
Add a search function in Rails.
Preparing to create a Rails application
I want to add a browsing function with ruby on rails
Create an app catalog site using CLI for Microsoft 365 with Docker
[Rails] DB design for EC site
[Rails Tutorial Chapter 5] Create a layout
Implemented mail sending function with rails
[Rails] Creating a new project with rails new
[Implementation procedure] Create a user authentication function using sorcery in Rails
Create a new app in Rails
Create an excel file with poi
Create an app with Spring Boot
Create a filtering function using acts-as-taggable-on
[Rails] A memo that created an advanced search form with ransack
Rails Tutorial Extension: I tried to create an RSS feed function
How to create a web server on an EC2 instance on AWS
Create My Page with Rails devise
Create exceptions with a fluid interface
Create a Maven project with a command