转载

Spree 电商系统开发概要

Spree 是什么

从产品角度来看, Spree 是一个基础的电商原型, 提供面向开发者的基础组件, 拥有一套自己的扩展语法, 帮助开发者快速建立独立电商系统.

从开发角度来看, Spree 是一个基于 Ruby on RailsRails Engine 项目, 通过 Rails Engine 的拆分, 将电商核心逻辑, 前端展示, 后台管理, 用户认证, 网关支付, API等分离出来. 并基于 Rails Engine 提供一套自身的扩展语法, 可以 "轻易地" 进行一些定制.

Spree 的核心

Spree 是一个 Rails 项目, 更是一个 Rails Engine 的项目.

Rails Engine 是 Rails 3.1 开始支持的一种分离 Rails 应用的技术方案, 它可以让某些独立的模块直接拆为一个 Gem 包. (什么是 Gem: http://guides.rubygems.org/what-is-a-gem/ )

例如, 我写的 Lina 和著名的 devise 组件都是一个完整的 Rails Engine 项目.

每一个 Rails Engine 都是一个相对独立的 Rails 项目, 它有自己的初始化加载方式, 独立的 controller, model, view, js, css.

良好的 Rails Engine 都有自己独立的模块隔离, 所以它们不会影响我们自己的代码. 但通过 Ruby 的强大的元编程能力, 我们可以比较容易地修改它的内部代码, 这就是 Spree 的核心原理.

举个例子:

扩展一个新的页面, 先写一个 action:

# app/controllers/spree/home_controller_decorator.rb module Spree   HomeController.class_eval do     def sale       @products = Product.joins(:variants_including_master).where('spree_variants.sale_price is not null').uniq     end   end end 

view:

# app/views/spree/home/sale.html.erb <div data-hook="homepage_products">   <%= render 'spree/shared/products', :products => @products %> </div> 

Rails 会自动优先从根项目目录寻找对应的 view, 所以优先渲染了我们的 view. 而 action 则是直接通过 class_eval 来向 HomeController 插入了一个新的方法来实现的.

这就是 Spree 定制的秘密. 当然这里只简单介绍一下, 接下来会专门介绍 Spree 的所有扩展的概念.

那 Spree 是如何分解功能模块呢?

  1. spree_core

    所有核心的内容都在 spree core 里, 包括订单处理, 价格调整, 运费管理, 支付等等. 它们构成了 Spree 的基础. 细一点来说, spree core 有核心 model 定义, 基础 controller 的 helpers, 基础的 Spree JS 定义, 基础样式, 测试支持.

  2. spree_frontend

    所有对普通买方的页面实现, 首页(home), 下单(checkout), 订单管理(order), 商品(product), 购物车(store), 分类(taxon).

  3. spree_backend

    管理员后台系统, 用户管理, 角色管理, 订单管理, 返单管理等等.

  4. spree_api

    利用 rabl 提供所有 JSON API 服务, API 功能类似于 frontend.

  5. spree_cmd

    不是 Rails Engine, 它只是一个 gem, 利用 thor 提供安装 Spree 和生成 Spree 扩展的命令工具.

  6. spree_sample

    不是 Rails Engine, 只是一个基于 rake 的一个任务, 提供一些示例的数据.

由上可知, Spree 对开发者来说, 最为关键的是, 如何去定制我们自己的功能, 下面是关键.

Spree 扩展的概念

Spree 扩展( extension )是它对比 ecshop 等独立建站系统的核心优势, 定制性很强. 那来看看它到底是怎么运作的?

首先, Spree 扩展也是一个 Rails Engine, 所以 Rails Engine 的定制方式它都可以用:

  1. 通过覆盖文件的方式定制

    Rails 加载页面和控制器时, 有一个先后顺序, 如果你的 Rails Engine 中有一个同名的文件, 则不会去找下一个, 很多时候, 通过这种方式定制会很方便.

  2. 通过 class_eval 去修改

    class_eval 是 Ruby 元编程中非常重要的一个功能, 可以让你临时打开一个已经定义好的类, 向其中定义新方法, 覆写已有方法. 而 Spree 定义了一套复写的 DSL. 控制器扩展:

    module Spree   HomeController.class_eval do     def sale       @products = Product.joins(:variants_including_master).where('spree_variants.sale_price is not null').uniq     end   end end 

    模型扩展:

    module Spree Variant.class_eval do alias_method :orig_price_in, :price_in def price_in(currency)   return orig_price_in(currency) unless sale_price.present?   Spree::Price.new(:variant_id => self.id, :amount => self.sale_price, :currency => currency) end end end  

    视图扩展( 覆写 ):

    <div data-hook="homepage_products"> <%= render 'spree/shared/products', :products => @products %> </div> 

    还有一种叫 Deface 的部分改写的方法:

    Deface::Override.new(:virtual_path  => "spree/checkout/registration",                  :insert_before => "div#registration",                  :text          => "<p>Registration is the future!</p>",                  :name          => "registration_future") 

    这样可以轻易地在某个视图中插入一段或替换一段新的视图.

    基本上, 以上就是 Spree 扩展所有可支持的扩展方式, 本质还是 Rails 应用开发.

我们应该怎么做

我们拥有几种手段来定制与开发新的 Spree 应用.

第一种: fork 流

直接 fork 过来 spree 的源码, 然后有不满意的地方直接修改, 简单粗暴. 适合对 Spree 有大的调整的情况.

第二种: 扩展型

不修改原有 spree 任何源码, 每次扩展, 创建一个独立的 Spree 扩展, 利用 Spree 的扩展技术来修改代码, 达到目的. 非常清晰的代码, 但开发与测试成本都明显高.

第三种: Rails 复用

既然 Spree 扩展只是一个 Rails Engine, 我们可以直接在 Rails APP 中, 利用 Spree 扩展特性来定制我们的功能. 效率最高, 但这样子对 Spree 后续的升级造成一定的麻烦.

第四种: 单一 Spree 扩展, Rails APP 只定制一些页面

我们如果想稍稍灵活一点, 可以只创建一个 Spree 扩展, 将需要定制 Spree 的功能全放在里面, Rails APP 只做一些基础修改.

这样的优点在于对 Spree 的冲击小一点, 未来还可以有升级的可能, 代码相对好一点.

后续研究

除以上分析外, 我们需要继续研究的东西也不多了, 但也十分关键:

  1. Spree 电商核心逻辑的分析, 各个表关联关系.
  2. 定制化 checkout 流程的分析
  3. 一些简单的选项
正文到此结束
Loading...