订单状态切换功能: aasm状态机

网上商店,消费者下单后,形成了订单,在不同情形下,订单的状态也会不同。因此,我们需要有一个功能,能使订单从某种状态切换(变化)成另一种状态。这就是订单状态的切换功能,而aasm状态机正是实现这一功能的工具。

逻辑梳理


在开始实现这种功能,使用aasm状态机之前。我们需要先问自己几个问题:

  1. 订单状态有多少种
  2. 订单切换事件有多少种
  3. 在什么情况下,触发订单切换事件

弄清楚这些问题,理清它们之间的逻辑关系,有利于我们规划使用aasm,达到功能切换的目的。

我先放一张图,来形象化描述问题1、问题2:

订单状态切换功能: aasm状态机_第1张图片

进一步阐释

  1. 订单状态
  • 种类: 6种
  • 分别是: order_placed, paid, shipping, shipped, good_returned, order_cancelled
  1. 订单切换事件
  • 定义:它指的是订单从一种或几种状态切换/转变成另一种状态的过程
  • 种类:5种
  • 分别是:A, B, C, D, E
  • 举例说明:比如A事件的发生,意味着订单状态从order_placed改变为paid,最终结果是订单状态为paid
  1. 触发订单切换事件的条件
  • 定义:它指的是,在满足某种条件或情形下,我们就会去触发订单切换事件;从行为的先后顺利角度看,执行订单切换事件行为的“前一个行为”就是“触发订单切换事件的条件”
  • 举例说明:比如触发A事件的条件,是消费者下完订单、点击付款提交后

具体案例


Part I

解决问题1和问题2,即安装aasm以及定义订单状态和订单切换事件

Step1: 安装aasm

gem 'aasm'

执行bundle install rails s

Step2: 在orders table里,产生aasm_state栏位,用来记录订单状态
执行rails g migration add_aasm_state_to_orders
在刚才的migration 文件里,增加两行

add_column :orders, :aasm_state, :string
add_index :orders, :aasm_state

执行rake db:migrate

Step3: 在app/models/order.rb文件里,增加以下内容

include AASM
aasm do
  state :order_placed
  state :paid
  state :shipping
  state :shipped
  state :good_returned
  state :order_cancelled

  event :make_payment do
    transitions from: :order_placed, to: :paid
  end

  event : ship do
    transitions from: :paid, to: :shipping
  end

  event :deliver do
    transitions from: :shipping, to: :shipped
  end

  event :return_good do
    transitions from: :shipped, to: :good_returned
  end 

  event :cancel_order do
    transitions from: [:order_placed, :paid], to: :order_cancelled
  end

end

说明:以上步骤,解决了问题1、问题2,

Part II

解决问题3,定义触发订单切换事件的条件,此处分别针对触发事件A, B, C, D, E的条件

(一)定义触发订单切换事件A的条件

条件是:消费者下定单且提交付款之后

Step1: 定义好routing,在member do下面加入两行

resources :orders do
  member do
    post :pay_with_alipay
    post :pay_with_wechat
  end
end

Step2: 付款这个action,通常是在app/controllers/orders_controller.rb里定义的,比如是用支付宝或微信付款,则这个action可以加入一行: @order.make_payment

def pay_with_alipay
  @order = Order.find(params[:id])
  @order.set_payment_with("alipay")
  @order.make_payment
  flash[:notice] =  "已用支付宝完成付款"
  redirect_to order_path(@order)
end

def pay_with_wechat
  @order = Order.find(params[:id])
  @order.set_payment_with("wechat")
  @order.make_payment!
  flash[:notice] =  "已用微信完成付款"
  redirect_to order_path(@order)
end

Step3: 在app/models/order.rb里,分别定义和支付相关的两个方法

def set_payment_with(method)
  self.update_columns(payment_method: method)
end

def pay!
  self.update_columns(is_paid: true)
end

Step3: 事件A的触发条件,包括两个:make_payment 以及 after_commit: :pay!
所以在order.rb里,重新定义事件A

  event :maket_payment, after_commit: :pay! do
    transitions from: :order_placed, to: :paid
  end


(二)定义触发订单切换事件B, C, D, E的条件

B: 管理员在后台点击“出货”按钮
C: 管理员在后台点击“已出货”按钮
D: 管理员在后台点击“退货”按钮
E: 管理员在后台点击“取消订单”按钮

Step1: 定义好routing, 在member do下面加入四行,这四行分别对应以上“触发订单切换事件B, C, D, E 条件"的routing

namespace :admin do
  resources :orders do
    member do
      post :ship
      post :shipped
      post :return
      post :cancel
    end
  end
end

Step2: 定义好以上条件的action,在app/controllers/admin/orders_controller.rb文件里,写以下代码,让action里包含了事件的执行

def ship
  @order = Order.find(params[:id])
  @ordr.ship!
  redirect_to admin_order_path(@order)
end

def shipped
  @order = Order.find(params[:id])
  @ordr.deliver!
  redirect_to admin_order_path(@order)
end

def return
  @order = Order.find(params[:id])
  @ordr.return_good!
  redirect_to admin_order_path(@order)
end

def cancel
  @order = Order.find(params[:id])
  @ordr.cancel_order!
  redirect_to admin_order_path(@order)
end

Step3: 写好view,让每个订单可以因其不同状态被管理员在后台点击切换
新增一个文件touch app/views/admin/orders/_state.html.erb
在该文件里,写入

<% case order.aasm_state do %> <% when "order_placed" %> <%= link_to("取消订单", cancel_admin_order_path(order), method: :post, class: "btn btn-default btn-sm") %> <% when "paid" %> <%= link_to("取消订单", cancel_admin_order_path(order), method: :post, class: "btn btn-default btn-sm") %> <%= link_to("出货", ship_admin_order_path(order), method: :post, class: "btn btn-default btn-sm") %> <% when "shipping" %> <%= link_to("已出货", shipped_admin_order_path(order), method: :post, class: "btn btn-default btn-sm") %> <% when "shipped" %> <%= link_to("退货", return_admin_order_path(order), method: :post, class: "btn btn-default btn-sm") %> <% when "good_returned" %> 已退货 <% when "order_cancelled" %> 已取消订单 <% end %>

在app/views/admin/orders/show.html.erb里,新增一行

<%= render "state", order: @order %>


总结


经过逻辑梳理,理解运作机制,能帮助我们事先规划好,便于后续实作代码。
通过具体案例,运用上面的逻辑梳理,落到实处写代码,实现订单状态切换的功能。

你可能感兴趣的:(订单状态切换功能: aasm状态机)