保华的Rails学习笔记

购物网站代码重构(一)

1、用before_action进行代码重构

在oders_controller中,发现在show、pay_with_alipay、pay_with_wechat中,都包含有@order = Order.find_by_token(params[:id])这一行代码,我们可以把@order = Order.find_by_token(params[:id])写到一个method中,并且在before_action中写入这个method,重构后的代码如下:

class OrdersController < ApplicationController
  before_action :authenticate_user!, only: [:create]
  before_action :find_order_by_token, only: [:show, :pay_with_alipay, :pay_with_wechat]
  def create
    @order = Order.new(order_params)
    @order.user = current_user
    @order.total = current_cart.total_price

    if @order.save

      current_cart.cart_items.each do |cart_item|

        product_list = ProductList.new
        product_list.order = @order
        product_list.product_name = cart_item.product.title
        product_list.product_price = cart_item.product.price
        product_list.quantity = cart_item.quantity
        product_list.save
      end

      OrderMailer.notify_order_placed(@order).deliver!
      redirect_to order_path(@order.token)
    else
      render 'carts/checkout'
    end
  end

  def show
    @product_lists = @order.product_lists
  end

  def pay_with_alipay
    @order.set_payment_with!("alipay")
    @order.make_payment!
    redirect_to order_path(@order.token), notice: "使用支付宝完成付款"
  end

  def pay_with_wechat
    @order.set_payment_with!("wechat")
    @order.make_payment!
    redirect_to order_path(@order.token), notice: "使用微信成功完成付款"
  end

  def apply_to_cancel
    @order = Order.find(params[:id])
    OrderMailer.apply_cancel(@order).deliver!
    flash[:notice] = "已提交申请"
    redirect_to :back
  end


  private

  def find_order_by_token
    @order = Order.find_by_token(params[:id])
  end

  def order_params
    params.require(:order).permit(:billing_name, :billing_address, :shipping_name, :shipping_address)
  end

end

2、利用继承重构

app/controllers/admin/orders_controller.rb和app/controllers/admin/products_controller.rb中
都包含有代码:

layout "admin"
  before_action :authenticate_user!
  before_action :admin_required

我们可以新建立一个admin_controller.rb,把这三行代码加入到这个admin_controller中

class AdminController < ApplicationController
  layout "admin"
  before_action :authenticate_user!
  before_action :admin_required
end

然后app/controllers/admin/orders_controller.rb和app/controllers/admin/products_controller.rb
继承这个admin_controller

-class Admin::OrdersController < ApplicationController
-  layout "admin"
-
-  before_action :authenticate_user!
-  before_action :admin_required
+class Admin::OrdersController < AdminController
-class Admin::ProductsController < ApplicationController
-  layout "admin"
-  before_action :authenticate_user!
-  before_action :admin_required
+class Admin::ProductsController < AdminController

3、mixin 与 ActiveSupport::Concern

在app/models/order.rb中

before_create :generate_token

  def generate_token
    self.token = SecureRandom.uuid
  end

这几行代码,其它地方也可能会用到,如果都复制、粘贴这三行,显的有些麻烦,我们可以在app/models/concerns
下边建立一个tokenable.rb文件,这个文件内容如下:

module Tokenable

    extend ActiveSupport::Concern

    included do
      before_create :generate_token
    end


    def generate_token
      self.token = SecureRandom.uuid
    end
end

现在修改app/models/order.rb,把之前的

before_create :generate_token

  def generate_token
    self.token = SecureRandom.uuid
  end

去掉,在app/models/order.rb上边添加include Tokenable,变为:

class Order < ApplicationRecord
   include AASM

+  include Tokenable
   aasm do
     state :order_placed, initial: true
     state :paid
   end

-  before_create :generate_token
-  def generate_token
-    self.token = SecureRandom.uuid
-  end

进行这三步重构后,代码看起来要清爽一些了