我想清理和重构订单控制器中的create方法代码,我读到使用服务对象是一种好习惯。从这里的可怕代码开始:
def create
if current_user.orders.where(paid: false).present?
order = current_user.orders.last
order_id = order.id
product_id = @product.id
@product.ordinable = false
@product.save
order_amount = order.amount
if order.products << @product
order.products.each do |x|
@order_amountnew = order_amount + x.price
end
order.amount = @order_amountnew
order.save
respond_to do |format|
format.html { redirect_to products_path, notice: 'Product added to the cart!' }
end
else
respond_to do |format|
format.html { redirect_to products_path, notice: 'There was a problem while adding the product to the cart!' }
end
end
else
product_id = @product.id
order = current_user.orders.new
order.save
order_id = order.id
@product.ordinable = false
@product.save
order_amount = order.amount
if order.products << @product
order.products.each do |x|
@order_amountnew = order_amount + x.price
end
order.amount = @order_amountnew
order.save
respond_to do |format|
format.html { redirect_to products_path, notice: 'Product added to the cart!' }
end
OrderPaidCheckJob.set(wait: 3.minutes).perform_later(order_id)
else
respond_to do |format|
format.html { redirect_to products_path, notice: 'There was a problem while adding the product to the cart!' }
end
end
end
end
我想将方法基本上分为两部分,因此我在services文件夹中创建了两个模块,如下所示。 我叫第一个order_present_create_service
module OrderPresentCreateService
class << self
def create(params)
order = current_user.orders.last
order_id = order.id
product_id = @product.id
@product.ordinable = false
@product.save
order_amount = order.amount
if order.products << @product
order.products.each do |x|
@order_amountnew = order_amount + x.price
end
order.amount = @order_amountnew
order.save
respond_to do |format|
format.html { redirect_to products_path, notice: 'Product added to the cart!' }
end
else
respond_to do |format|
format.html { redirect_to products_path, notice: 'There was a problem while adding the product to the cart!' }
end
end
end
end
end
然后我打电话给第二个order_new_create_service
module OrderNewCreateService
class << self
def create(params)
product_id = params[:id]
order = current_user.orders.new
order.save
order_id = order.id
@product.ordinable = false
@product.save
order_amount = order.amount
if order.products << @product
order.products.each do |x|
@order_amountnew = order_amount + x.price
end
order.amount = @order_amountnew
order.save
respond_to do |format|
format.html { redirect_to products_path, notice: 'Product added to the cart!' }
end
OrderPaidCheckJob.set(wait: 3.minutes).perform_later(order_id)
else
respond_to do |format|
format.html { redirect_to products_path, notice: 'There was a problem while adding the product to the cart!' }
end
end
end
end
end
这是我的新控制器:
def create
if current_user.orders.where(paid: false).present?
OrderPresentCreateService.create(params)
else
OrderNewCreateService.create(params)
end
end
我只是按照本文here进行操作。 当我尝试创建订单时,现在出现此错误:
OrderNewCreateService:Module的未定义局部变量或方法“ current_user”
在一开始,我在product_id = @ product.id时遇到了类似的错误,因此我在product_id = params [:id]中进行了更改,并使其以某种方式起作用。我在哪里做错了?
答案 0 :(得分:1)
如果我理解正确,那么任务就是从控制器重构原始动作。您的重构代码中列出了一系列问题,因此,为了使答案更短,让我跳过对其进行复审,而专注于原始操作。
我看到的问题是:
product_id
变量已初始化但未使用order_id
条件的第一个分支中的if
变量已初始化但未使用respond_to
块仅具有html
格式的条件。由于没有其他格式的代码,因此可以简化OrderPaidCheckJob.set
方法放置在redirect_to
之后,因此将永远不会调用它。要使其正常工作,请将其放在redirect_to
if
的条件,但操作以redirect_to
结束相同的路径,只有notice
发生了变化。因此,您可以直接设置notice
,然后将redirect_to
从if
中移出@product.ordinable = false; @product.save
可以简化为@product.update(ordinable: false)
。由于它位于if
的两个分支中,因此可以将其移出该块。if order.products << @product
。您何时认为这种情况是假的?如果将其添加到数据库时出现问题,它将引发异常。order.products.each do |x|
等块可以简化为order.amount = @order_amountnew = order_amount + order.products.last.price
(我怀疑您在这里有一个错误,因为您迭代了products
,但只保存了最后一个产品的结果)@order_amountnew
,但由于重定向而以后不再使用。我认为可以将其删除初步结果:
def create
@product.update(ordinable: false)
if current_user.orders.where(paid: false).present?
order = current_user.orders.last
order_amount = order.amount
if order.products << @product
order.amount = @order_amountnew = order_amount + order.products.last.price
order.save
notice = 'Product added to the cart!'
else
notice = 'There was a problem while adding the product to the cart!'
end
else
order = current_user.orders.new
order.save
order_id = order.id
order_amount = order.amount
if order.products << @product
order.amount = @order_amountnew = order_amount + order.products.last.price
order.save
OrderPaidCheckJob.set(wait: 3.minutes).perform_later(order_id)
notice = 'Product added to the cart!'
else
notice = 'There was a problem while adding the product to the cart!'
end
end
redirect_to products_path, notice: notice
end
看起来更好并且更具可读性?由于它仍然具有重复代码,因此可以将其进一步干燥。但是我建议您先解决我指出的问题,然后再进行重构。
答案 1 :(得分:1)
在我看来,您可以在不使用服务的情况下重构create
动作。 (我是服务的忠实拥护者。我只是认为您在这里不需要它们。)
首先,我将为您的User模型添加一些方法,如下所示:
class User < ApplicationRecord
def unpaid_orders
orders.where(paid: false)
end
def unpaid_orders?
unpaid_orders.any?
end
end
然后,我将amount
用作方法而不是属性,例如:
class Order < ApplicationRecord
def amount
products.sum(&:price)
end
end
然后,在您的控制器中,您可以执行以下操作:
delegate *%w(
unpaid_orders?
orders
), to: :current_user
def create
order = unpaid_orders? ? orders.last : orders.create!
@product.update(ordinable: false)
if order.products << @product
@notice = 'Product added to the Cart!'
OrderPaidCheckJob.set(wait: 3.minutes).perform_later(order.id) unless unpaid_orders?
else
@notice = 'There was a problem while adding the product to the cart!'
end
redirect_to products_path, notice: @notice
end
如果您不想在amount
上使用Order
作为方法,则可以执行以下操作:
delegate *%w(
unpaid_orders?
orders
), to: :current_user
def create
order = unpaid_orders? ? orders.last : orders.create!
@product.update(ordinable: false)
if order.products << @product
order.update(amount: order.products.sum(&:price))
@notice = 'Product added to the Cart!'
OrderPaidCheckJob.set(wait: 3.minutes).perform_later(order.id) unless unpaid_orders?
else
@notice = 'There was a problem while adding the product to the cart!'
end
redirect_to products_path, notice: @notice
end