【发布时间】:2015-01-06 06:36:27
【问题描述】:
我已经使用 Rails 有一段时间了,我的控制器代码开始失控(不是双关语。)我听说你想要瘦控制器和胖模型,对我来说这不是自然而然的在我的 Rails 进程中。
我将发布我的 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
如您所见,这是一个有点大的控制器。这是正常的吗?所有的逻辑都在那里发生。用户可能已经在购物车中有这个项目,这个项目可能没有库存,这个项目有一个容量并且用户试图订购更多。更何况我
我知道这不是一个典型的堆栈问题。没有什么是坏的,但我只是对我的代码感觉不好。
我不想提出“家庭作业”问题,但我会很感激有关如何使用模型重构控制器代码的建议。我会很感激参考和建议。
谢谢! 更新添加了购物车.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
【问题讨论】:
-
他们说,“Rails 控制器是每个 Rails 应用程序的汗水。”但是我确实觉得您的创建操作没有遵循单一责任原则,它担心创建行项目,还担心购物车的内容。有推车模型吗?做不需要持久化的模型是可以的。
-
我认为这是一个很好的问题。
-
那么 create 方法负责创建 line_items。但它还需要确保 line_item 不存在,并且数量可用。我是否只允许在保存后创建和组合相同的 line_items?
-
啊,这很有帮助。 Cart 是一个容器对象。我推荐使用容器模式。 Cart 应该有 addLineItem() 方法,检查发生在哪里,以及调用 create(委托责任)。 find_or_create 和 find_or_create_by 活动记录方法也可能有助于防止重复。对数量是多少、客户想要的数量或您的库存数量有点困惑?购物车对象应该只管理其中的 1 个。我会创建一个 Store 对象来管理库存。购物车向商店询问有效数量; Store 是另一种容器模式。
-
2 旁注,你可以使用 where_line_item_with 范围,范围::name, -> (prod_id) {where("product_id == ?", prod_id)} api.rubyonrails.org/classes/ActiveRecord/Scoping/Named/… 并且你可以使用 active记录回调(after_save/before_save)做检查api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
标签: ruby-on-rails ruby refactoring