我已经使用了一段时间的导轨,我的控制器代码开始失控(没有双关语。)我听说你想要瘦的控制器和胖模型,对我来说这个没有& #39;在我的轨道进程中自然而然。
我发布了我的rails应用程序的一个模型。
line_item #create
def create
@cart = current_cart
#product is built from base_product, after finding associated product
@base_product_id = params[:line_item][:base_product_id]
get_product_from_base_product
@line_item = @cart.line_items.build(
:product_id => @product_id,
:order_id => nil,
:weight => params[:line_item][:weight],
:quantity => params[:line_item][:quantity]
)
## Does a line item with the same product_id already exist in cart?
if @line_item.exists_in_collect?(current_cart.line_items)
#if so, change quantity, check if there's enough stock
if current_cart.where_line_item_with(@product_id).update_quantity(@line_item.quantity) == true
@line_item.destroy
redirect_to base_products_path
flash[:success] = "Detected Producted In Cart, Added #{@line_item.quantity} More to Quantity"
else
redirect_to cart_path
flash[:failure] = "Cannot Add To Cart, We Only Have #{@line_item.product.stock_qty} In Stock"
end
else
if @line_item.stock_check == true
if @line_item.save
respond_to do |format|
format.html { redirect_to base_products_path,
:notice => "(#{@line_item.quantity}) #{@line_item.product.base_product.title} Added to Cart." }
format.xml { render :xml => @line_item,
:status => :created, :location => @line_item }
end
else
format.xml { render :xml => @line_item.errors,
:status => :unprocessable_entity }
end
else
redirect_to base_products_path
if @line_item.product.stock_qty > 0
flash[:failure] = "Sorry! We Only Have #{@line_item.product.stock_qty} In Stock"
else
flash[:failure] = "Sorry! That Item Is Out Stock"
end
end
end
end
控制器方法:
private
def get_product_from_base_product
@product_id = Product.where(:base_product_id => @base_product_id).where(:size_id => params[:line_item][:size]).first.id
end
LineItem模型
class LineItem < ActiveRecord::Base
belongs_to :product
belongs_to :cart
after_create :set_order_weight#, :set_package_dimentions
after_update :set_order_weight#, :set_package_dimentions
#max capactiy here
def have_enough_product?
if self.product.stock_qty > self.quantity
return true
else
self.quantity = self.quantity_was
self.save
return false
end
end
def over_order_cap?
if self.quantity > 50
return true
end
end
def update_quantity(qty)
if self.have_enough_product? == true
self.quantity += qty
self.save
end
end
def stock_check
if self.product.stock_qty > self.quantity == true
return true
else
return false
end
end
def exists_in_collect?(items)
items.each do |item|
return true if self.product_id == item.product_id
end
return false
end
如您所见,这是一个有点大的控制器。这是正常的吗?所有的逻辑都在那里发生。用户可能已经在购物车中有此商品,此商品可能没有库存,此商品具有容量,并且用户正尝试订购更多商品。还有什么,我
我知道这不是一个典型的堆栈问题。什么都没有打破,但我对代码感觉不好。
我不想做一个&#39;作业&#39;问题,但我很欣赏有关如何使用模型重构控制器代码的建议。我很感激参考和建议。
谢谢! 更新添加了cart.rb
class Cart < ActiveRecord::Base
has_many :line_items#, dependent: :destroy
has_one :order
def where_line_item_with(prod_id)
line_items.where(:product_id => prod_id).first
end
def sub_total
self.line_items.to_a.sum { |item| item.total_price }
end
end
答案 0 :(得分:2)
我的回答不是因为我是专家,而是因为我最近才亲自经历过这个问题。对我而言,当我开始将我的应用程序放在测试套件下时,实现了。我在测试控制器操作时遇到了非常艰难的时间,因为他们做了很多不同的事情。
以下是我认为您应该将控制器的逻辑移动并分离为模型方法的几个原因:
重复使用代码。我发现不是在不同的控制器中编写相同的代码3或4次,而是在模型中编写一次(并测试一次!)并在控制器中调用这些方法。
测试。您可以在模型规范中测试一次(更容易在那里测试),而不是在3或4个控制器操作中测试相同的逻辑。它不仅可以节省您编写测试的时间,而且还可以消除您在控制器之间以不同的逻辑实现不同内容的可能性。
可读性。说实话,我没有读完整个create
行动,因为它不具备可读性。我有几个类似的动作,我讨厌尝试调试它们,因为很难跟踪发生的事情。将该逻辑移动到模型中(并将其分成更小,更具体的方法)使您可以专注于控制器应该做的事情(auth,指导,处理参数等)。
那么,如何重构呢?我在SO问题中读到了一些内容(现在无法找到),基本上说:如果逻辑处理资源的关联方式,它应该在模型中。我认为这是一个非常好的一般规则。我会从那里开始。如果你没有测试套件,我会同时添加它。