实现Product【一种规格一个价格】

写在前面

请一定要先把ajax的课程至少做过一遍,
不然,你可能会不知道我在说什么

相信我,如果你看完我所写的并最终实现下面的效果

你可以得到:

  1. 对电子商务数据库设计有初步的认识
  2. 透彻理解嵌套表单是在干嘛
  3. 通过对ajax上传数据与获取回调json的整合,让你发现ajax教程中的隐藏知识
  4. 实现一种规格一个价格,一种规格一个库存

主要效果图

心路历程

从刚开始做JDStore的时候,我就已经在思索这个事了。
但经过思考+搜索,发现这还设计电商数据库设计,
已经远远超出了我的知识水平,最终选择放弃。
但随着课程的深入,我时不时还是会把这个想法提出来,思考。
两周后,虽然我依然没有找到解决方案,但关于数据库设计的内容,
断断续续也看了一点,虽然内容很庞大很复杂,但已经有了一点点思路了,
直到ajax与百宝箱的课程放出来后,
我就知道,是时候实现这个心仪已久的功能了。
接下来,就是耗时一周的漫长的实践之路。

需求分析:

  1. 我们需要在product#index页面展示每一种产品 (比如iPhone 6)
  2. 每一种产品product#show页面中又能展示这种产品的不同规格 (比如 iPhone 6 64GB 土豪金 版)
  3. 每一个种产品下面的每一种规格都应该对应其不同的price和quantity和images

我的电商mini数据库Model设计:

  • Product Model用于商品index页面,进行展示和筛选
  • Variant Model分别代表该商品的每一种规格,用于商品展示show页面,实现每一种规格都有它单独的库存
  • Price Model则是与Variant配合使用,实现一种规格一个价格,可能有人会问,为什么不直接把价格写在variant里,我想说,其实我也不能给出明确的档案,不过阅读不少资料,都建议把Price单独拉出来做一个Model,所以我就照做了…

逻辑描述

这可能是最难的一块了,走了一圈下来,发现最耗时,最多坑的实际上是逻辑细节。
你费劲两三天,学了各种超课程范围的内容,结果发现,妈呀!想错了,白整了...

1. 用

  1. 进入show页面,后台提供该@product下所有@variant的 @colors选项 和 @sizes选项 以及所有@variants的库存之和
  2. 当在颜色菜单中选择一个颜色后(并为选择尺寸),要把当前选中颜色回传后台,并从后台拿到该颜色下,可以选择的尺寸,并更新尺寸的select表单,把没有的选项变灰,禁止用户选择;同时刷新库存和价格。
  3. 在已取颜色的情况下,选择了一个尺寸,要把当前选中颜色和尺寸都回传后台,并从后台返回的数据中,拿到库存和价格,并刷新相应的页面。
  4. 但没有选取颜色的情况下,选择了一个尺寸,回传后台并从后台拿到数据,刷新库存与价格(注意:这里,我并没有反过来去查找和限制颜色表单,是因为,这种
  5. 在没有选择颜色的情况下,选择了一个尺寸,又返回来选择一个颜色(由于防止互相影响的这种逻辑),我会,直接清空尺寸选择的选项,而只哪去颜色的选项,去回传给后台。 这样的逻辑是:你必须在选择了颜色的情况下,才能选择尺寸。 这样的设计我也是参考了很多小型电商网站,并尝试了很多以后发现,

但很明显,大家可能,更倾向于淘宝,京东的那种方框选择,下面也说一下这个逻辑

2. 淘宝/京东规格选择逻辑描述

这种点选的菜单就比

  1. 当选中一个颜色后,颜色数据传给后台,根据回传的数据,来把不能选择的尺寸变成灰色,并刷新页面库存与价格
  2. 在已选中一个颜色的情况下,选择一个尺寸,颜色和尺寸传给后台,根据回传数据,把不能选择的颜色也变灰
  3. 当已经选择了颜色和尺寸,反点已选中的颜色或已选中的尺寸,颜色或尺寸数据传给后台,根据回传数据,刷新可选的选项
  4. 先选尺寸再选颜色的逻辑也与1,2,3步一样。

技术细节详解

整个从前端到后端,从客户到管理员页面,使用到的技术有:

1.嵌套表单(1-to-1与1-to-many)(对Rails百宝箱一的延伸)



请注意我这里不仅仅在product下嵌套了一层one-to-many的variant
而且在variant下还嵌套了一层one-to-one的price
我自己称其为三重嵌套
这里面有好几个大坑,甚至最初,会让你觉得这是不可能做到的
在我不厌其烦的无数次试错之后,终于发现其中的奥妙

做完教材的两重嵌套,你只是知道,这叫做嵌套表单
当你跟着我做完三重嵌套,你就明白了什么叫嵌套表单,它的意义何在
嵌套表单的主要步骤就是

  1. 创建并配置model之间的关系
  2. 在html.erb中写相应的嵌套代码
  3. 在controller中的new和edit中分别加一行创建内嵌表单需要的对象,并在product_params中配置要接受的嵌套attributes

下面给大家展示我的html与controller中的相应内容
①此为admin/products/new.html.erb

②此为admin/products_controller.rb

至于model的内容,并没有什么不同的地方,与教材做法相同,就不在这里展示了

2.前端ajax的数据上传与回调

①在product/show.html.erb


②在它的下面接着写ajax的内容

③在routes中配置需要select_color请求地址

④在production_controller中

其实教材中有很多隐藏内容

你比如:

  • Ajax 4-4, 实际上是在告诉你,controller如何给前端ajax传值
  • Ajax 4-7,实际上是在告诉你,如何通过ajax给controller传值 当你发现前端到后端,后端到前端都可以同时联通的时候,就会猛然发现,你无所不能了,哈哈哈哈~~

建议

由于我的代码与自己的项目深度整合,并不太适合写一个从0开始的教程
所以给大家的建议就是

  1. 先看完教程中ajax与rails百宝箱的内容
  2. 再来看我这篇代码详解
  3. 然后对照着代码详解,同时可参看我github上的代码
  4. 然后自己在自己的项目里实现一遍
  5. 相信我,当你最终把这个实现以后,有一扇门为你打开,以为当你明白ajax是怎么回事以后,你发现你的项目可以进化的太多了,你会无比兴奋,哈哈哈
老规矩,如果对你有用,你懂的



小知识点

给数组去重
[1,2,3,3,3,4,4,5,5,6,6].uniq
得到=>  [1,2,3,4,5,6]
present?,empty?,blank?的区别

present? 是ruby的语法,判断是否为nil
empty? 是ruby的语法,判断是否为空,如:[]
blank? 是Rails的语法,判断是否同时满足present?与empty?

对["100cm","90cm", "110cm", "80cm"]进行数字排序
["100cm","90cm", "110cm", "80cm"].sort_by{ |i| i[0..-3].to_i }
jquery获取所有直接之元素
$("#xxxxxx").children()
js数组的循环遍历
an_array.each(function(index){
        ........
})
js数组查询数组中是否包含某元素以及其index
var results = an_array.indexOf(str);
// 如果没找到results就是-1

//如果要做判断就可以拿results做判断
js把获取的string解析为Integer
var num = parseInt($(this).val());



往期分享

吉翔

【第三方登录】用Devise+OmniAuth实现第三方登录
商品无限级分类
Github仓库备份
中文字体自定义
魔改大赛这样开始比较快

董明娟

Panel+Grid作出清爽购物车
bootstrap实现About翻转卡片
商店大赛倒计时第五天(内含时间小套路)