赵龙 全栈之路

【魔改经验分享04】一张图快速理解“购物车的基本逻辑”

| Comments

购物网站.用户

全栈营教材 “Rails 实战:购物网站” 的核心可以理解为 “rails 101” 框架使用 “购物车系统” ,再加上其他的辅助功能。本文就是帮助大家快速理解最重要的核心——“购物车系统”。

购物车系统的主要角色是 “用户” 与 “购物车” 。在首图中的红框部分,用户与网站前端页面的交流由文件 config/routes.rb 处理,该文件的作用可以类比为分配公司网络的大型路由器。相关内容在全栈营教材 “rails 101” 的 “4-9(解说)Rails 的 CRUD 与 RESTful” 有详细解释。

简单说明下:用户进入购物网站首页后,看到自己喜欢的商品点击图片进入商品介绍页。在用户进行这个简单的操作中,用户向网站发送了读取该商品介绍页的 GET 请求,网站收到请求后及时反馈信息给给用户。这个过程会生成用户想要的商品介绍页与对应的网址,网站与用户就是以这样的基本逻辑进行交流的。

config/routes.rb
# ...略
  resources :products do   //resources.资源;products.商品;
    member do              //member.网站会员;do.执行以下操作;
      post :add_to_cart    //post:新增请求;add_to_cart.加入购物车;
    end
  end
# ...略


购物网站.购物车

购物车整体运行的基本逻辑

方便大家快速理解,将 “购物车系统” 类比为一个餐馆。在首图的红框部分将 “购物车系统” 大致分为三部分:

  • “Views.用餐区” ; “Controller. 前台” ; “Model.后厨” 。
    • “Views.用餐区” :客户在进入餐厅之后,一切操作都是在这里进行,例如 “点餐.商品加入购物车” , “好几道菜同时下单.购物车页面” , “客户结账.订单结账页面” 等等。
    • “Controller. 前台” :所有的客户在餐厅下单后,订单集中在前台分类处理,确定交给 “Model.后厨” 的哪一位 “厨师.model” 做菜。“Model.后厨” 完成一道菜后,先让 “Controller. 前台” 过目,再决定交给哪一位客户。
    • “Model.后厨” :这是 “购物车系统” 最重要、最精华的部分!客户下单后,能不能让客户满意,就是看 “Model.后厨” 最终的处理结果了。

将 “购物车系统” 这样分为三部分能极大的提高运作效率。如果去掉 “Controller. 前台” ,会使整个购物车系统的复杂度指数级增长。“Views.用餐区” ; “Controller. 前台” ; “Model.后厨” 三部分取首字母也被缩写为 “MVC” 。

current cart

现实中,所有的客户进入超市购物都会配备一辆购物车,无论客户是否为超市的会员。 current cart 这个代码就是判断客户是否有一辆购物车,如果没有就指派一辆新的购物车给客户。

全栈营教材 “Rails 实战:购物网站” :5-4 Step 3: 购物车设计 Part 2 ,该页教材的最后就有这段代码的详细解释。

app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
# ...略

  helper_method :current_cart

  def current_cart
    @current_cart ||= find_cart
  end

  private

  def find_cart
    cart = Cart.find_by(id: session[:cart_id])
    if cart.blank?        //blankk.空白
      cart = Cart.create
    end
    session[:cart_id] = cart.id 
    return cart           //return.返回
  end
end

通过 Controller 理解购物车的运行

大家继续关注首图的红框部分,我尝试让大家快速理解购物车如何运行。当用户在商品介绍页点击加入购物车的 “Views.按钮” 时, “Controller. 控制器” 接受到了用户请求使用以下判断式代码,从后台数据库( “Model.模型” 在大多数的情况配合数据库处理)中找到对应的商品信息添加到用户的专属 “cart.购物车” 中,并将执行完毕的操作结果反馈到 “Controller. 控制器” , “Controller. 控制器” 再将这个结果反馈到用户。客户浏览网站的顶部导航栏的显示购物车内的商品总数会 +1 。首图的红框中的 1 > 2 > 3 > 4 。

app/controllers/products_controller.rb
class ProductsController < ApplicationController
# ...略

  def add_to_cart       //添加到购物车
    @product = Product.find(params[:id])   
    //这段代码表示从网站的商品仓库找到对应的商品且确定下来;params.参数
    
    redirect_to :back
    //redirect.重定向;返回
  end
end

注意: @ 代表全局变量,没有 @ 则网站无法判断出到底是哪个商品,会出现报错,这是因为 product 不是唯一的,网站有许许多多的 product 形成了一个巨大的 “Product.all.商品仓库” ,如果直接给出一个 product 相当于整个商品仓库都加入到用户的购物车,网站会出现严重的 bug 。

购物车中的 4 个主要 Model

user.用户:网站需要知道是哪位用户在浏览。
product.商品:网站需要知道商品仓库中的哪些商品被加入购物车。
cart.购物车:网站需要知道用户是否拥有购物车且判断出是哪一辆购物车。
cart_item.商品条目:网站需要知道加入购物车的商品信息。

注意: “cart_item.商品条目” 可以形象的类比为 “Product.all.商品仓库” 内存放每一个商品的箱子,有的 “product.商品” 的箱子像集装箱这么大,有点只有一个小篮子一样大。购物车中的每一个 “product.商品” 的 “cart_item.商品条目” 是从 “Product.all.商品仓库” 中对应的 “cart_item.商品条目” 取出来的,并重新做出一个小的 “cart_item.商品条目” 存放在每一个用户的 “cart.购物车” 中。全栈营教材 “Rails 实战:购物网站”:5-3 Step 2: 购物车设计 Part 1, 也有相关的解释。可以将两个解释互相对应看,方便理解。

Model 的基本逻辑关系

购物车中的 4 个主要 Model 的基本逻辑关系
user
  has :cart
  //用户拥有一辆购物车
  
product
  belongs_to :carts;
  //商品属于许多辆购物车
  
  belongs_to :Product.all;
  //商品属于整个网站的商品仓库

  
cart
  has many :products;
  //购物车拥有需要的商品
  
  has many :cart_items;
  //购物车拥有需要的商品条目信息

   
cart_item
  belongs_to :cart;
  //商品条目信息属于许多辆购物车
  
  belongs_to :product;
  //商品条目信息属于许多商品

Model 与数据库中的关系的详解

已经建立的 Model —— cart_item ,需要在数据库中添加交易记录,并修改。

db/migrate/xxxx_create_cart_items.rb
class CreateCartItems < ActiveRecord::Migration[5.0]
  def change
    create_table :cart_items do |t|  
    // |t| 在这段代码代表cart_items t 可以换成任意字母
    
+     t.integer :cart_id
      //integer.整数;

+     t.integer :product_id
+     t.integer :quantity, default: 1
      //quantity.数量;default.默认

      t.timestamps
      //timestamps.时间戳
    end
  end
end

注意: db/migrate/XXX 文件修改后,终端必须执行 bundle install 指令,数据库才会正式修改。

app/models/cart.rb
class Cart < ApplicationRecord
# ...略

  def add_product_to_cart(product)
    ci = cart_items.build
    //ci 在这段 def..end 代码中,赋予了 cart_items.build 的含义。build.建造
    
    ci.product = product
    //从整个商品仓库中找到对应的商品
    
    ci.quantity = 1
    //从找到的商品的集装箱中拿出 1 
    
    ci.save
    //save.保存
  end
  
# ...略
end

注意:ci.product 未使用 @ ,因为文件 app/controllers/products_controller.rb 已经在 “Product.all.商品仓库” 中确定了是哪一个 “product.商品” ,没有必要再次重复确认。

app/controllers/products_controller.rb
class ProductsController < ApplicationController
  def index
    @products = Product.all
  end

  def show
    @product = Product.find(params[:id])
    //从商品仓库中找到对应商品的 id 参数信息
  end

# ...略
end

好啦,本篇《魔改经验分享》结束了,感谢各位助教与小伙伴的无私分享与帮助,希望能帮助各位小伙伴。

本文由 赵龙 与 彭皓heric 合作完成,如果您觉得这篇《魔改经验分享》很赞,欢迎您浏览我们的作品:

点击》知识猎人公会.猎人学院《点击

如果您认为这个作品不错,冒昧地恳请您投上一票。

Comments

comments powered by Disqus