Tính năng Giỏ Hàng, Shopping cart trong Rails

Ở bài viết này mình sẽ tóm tắt cách dùng Ruby on Rails và Ajax để tạo 1 app có chức năng “thêm vào giỏ hàng” như các shop online. ! 😊😊 Bài viết được viết với mục đích đầu tiên là để chính bản thân đọc lại khi có thời gian nên sẽ rất

Ở bài viết này mình sẽ tóm tắt cách dùng Ruby on Rails và Ajax để tạo 1 app có chức năng “thêm vào giỏ hàng” như các shop online. ! 😊😊
Bài viết được viết với mục đích đầu tiên là để chính bản thân đọc lại khi có thời gian nên sẽ rất ngắn gọn và lược đi phần frontend. 😂
Mọi người cùng đọc và góp ý nhé.


Mở đầu

App lần này của mình sẽ là app order sách.

Ruby version: 2.7.2
Rails version : 6.1.5
Database : default SQLite3

1. Tạo Model và Controller

Tạo Model booktitle là tên sách và price là giá sách

rails g model book title:text price:integer

Controller books với 2 chức năng là create và destroy

rails g controller books create destroy

Model order dùng để lưu lại lịch sử order. quantity là số lượng mỗi lần order, total_price là số tiền mỗi lần order.
Trong table order thì book_id sẽ là khóa ngoại.

rails g model order quantity:integer total_price:integer book:references

Controller orders có 2 chức năng là create và destroy

rails g controller orders create destroy

tạo trang homepage cho app qua file index của controller homes

rails g controller homes index

Khởi tạo database bằng lệnh migrate

rails db:migrate

2. Tạo tính năng Giỏ Hàng

Tạo database book bằng seed
seed.rb

Book.create(title:"Java", price:50)Book.create(title:"RoRs", price:80)Book.create(title:"C", price:70)
rails db:seed

Config file routes.rb

Rails.application.routes.draw do
  get 'books/create'
  get 'books/destroy'

  resources :orders, only:[:create,:destroy]
  resources :homes, only:[:index]
  root "homes#index"# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.htmlend

resources :orders chỉ áp dụng cho method createdestroy.
resources :homes chỉ áp dụng cho method index.

book.rb

classBook<ApplicationRecord
    has_many :ordersend

order.rb

classOrder<ApplicationRecord
    belongs_to :bookend

Homepage của app sẽ được customize qua file homes/index.html.erb

<h1>Shop</h1>

<% @books.each do |book| %>
    <%= book.id %> - <%= book.title %> - <%= book.price %>¥
    <%= form_for @order, remote: true do |f| %>
    	<%= f.hidden_field :book_id, :value => book.id %>
    	<%= f.number_field :quantity, :value => 1, :min => 1 %>
    	<%= f.submit "Add to cart" %>
	<% end %>
<% end %>

<hr>
<div class="total-amount">
    <%= render "orders/total" %>
</div>
<div class="reception">
    <% @orders.each do |order| %>
            <%= render "orders/order", order: order %>
    <% end %>
</div>

Do ở phần sau mình có dùng thêm tính năng của Ajax nên trong form_for phải có thêm remote: true.

Tạo mới file orders/_total.html.erb, tổng tiền cần thanh toán sẽ được gọi qua file partial này.

<h3>Ordered List -- Total amount: <%= Order.sum(:total_price) %>¥</h3>

Tạo mới file orders/_order.html.erb, danh sách order sẽ được hiển thị qua file partial này.

<%= order.id %> - <%= order.book.title %> - 
<%= order.book.price %>¥ x <%= order.quantity %> = 
<%= order.total_price %>¥<br>

Config controller homesorders

homes_controller.rb

classHomesController<ApplicationControllerdefindex@books=Book.all
      @orders=Order.order("created_at DESC")@order=Order.newendend

orders_controller.rb

classOrdersController<ApplicationControllerdefcreate@order=Order.new(order_params)@order.total_price =@order.book.price *@order.quantity
    respond_to do|format|if@order.save
            format.js {}endendenddefdestroyendprivatedeforder_params
    params.require(:order).permit(:book_id,:quantity,:total_price)endend

3. Áp dụng Ajax

Đến đây tính năng Thêm vào giỏ hàng đã cơ bản được hoàn thành. Tiếp theo mình sẽ áp dụng ajax vào app để các thao tác mượt mà hơn. Các bạn có thể xem thêm cách xây dựng 1 app Ajax đơn giản qua bài mình đã viết đây

https://viblo.asia/p/app-ajax-don-gian-trong-rails-bWrZnAmrKxw

Import CDN của ajax vào file application.html.erb

<!DOCTYPEhtml><html><head><title>Testapp</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
    <scriptsrc="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head><body>
    <%= yield %>
  </body></html>

Trong folder app/views/orders, đổi tên file create.html.erb thành create.js.erb . Sau mỗi lần bấm button Add to cart thì file create.js.erb sẽ được gọi.

$(".reception").prepend("<%= j render @order %>");
$(".total-amount").html("<%= j render "orders/total" %>");

Câu lệnh <%= j render @order %> là cách viết tắt của <%= escape_javascript(render @order) %>.
Nó giúp lệnh render của chúng ta tránh bị lỗi ký tự khi render file partial. Các bạn có thể đọc thêm về escape_javascript ở đây
https://stackoverflow.com/questions/1620113/why-escape-javascript-before-rendering-a-partial Hoặc
https://apidock.com/rails/ActionView/Helpers/JavaScriptHelper/escape_javascript

Thành quả

Đến đây app đặt sách đơn giản với tính năng thêm vào giỏ hàng đã được hoàn thành. Truy cập vào localhost và xem thành quả nào ^^.

Tổng kết

Bằng cách làm tương tự, ta hoàn toàn có thể làm thêm tính năng xóa sản phẩm và chỉnh sửa số lượng sản phẩm trong ordered list.
Mọi người cùng đọc và góp ý nếu bài viết có thiếu sót nhé. 😊😊

Nguồn: viblo.asia

Bài viết liên quan

WebP là gì? Hướng dẫn cách để chuyển hình ảnh jpg, png qua webp

WebP là gì? WebP là một định dạng ảnh hiện đại, được phát triển bởi Google

Điểm khác biệt giữa IPv4 và IPv6 là gì?

IPv4 và IPv6 là hai phiên bản của hệ thống địa chỉ Giao thức Internet (IP). IP l

Check nameservers của tên miền xem website trỏ đúng chưa

Tìm hiểu cách check nameservers của tên miền để xác định tên miền đó đang dùn

Mình đang dùng Google Domains để check tên miền hàng ngày

Từ khi thông báo dịch vụ Google Domains bỏ mác Beta, mình mới để ý và bắt đầ