[英]Rails 3.2 Simplify Controller with Model Methods on has_many :through
Most questions I've seen with skinnying up controllers deals with a simple model relationships. 我在瘦控制器上看到的大多数问题都涉及简单的模型关系。 My question is if you're updating a many to many form with multiple parameters and their associated arrays, how do you simplify the task by moving it all to a model method? 我的问题是,如果要更新具有多个参数及其关联数组的多对多表单,如何通过将其全部移至模型方法来简化任务? For example take a look at the ridiculously large controller below. 例如,看下面的一个荒谬的大型控制器。 What's the simplest way of dealing with this unholy mess? 处理这个邪恶的混乱的最简单方法是什么? I'm not looking for a syntactically perfect answer but need a general consensus on a direction to go with this. 我不是在寻求语法上完美的答案,而是需要就此达成共识。
def update
@shipment = Shipment.joins(:products).find(params[:id], :readonly => false)
@shipment.update_attributes(params[:shipment])
@shipment_products = params[:product_shipments]
@product_shipment_array= array_from_hash(@shipment_products)
@shipment.product_shipments.each do |product_shipment|
product_shipment.update_attributes(:qty_shipped => params[:product_shipments][product_shipment.id.to_s][:qty_shipped], :pickup_item => params[:product_shipments][product_shipment.id.to_s][:pickup_item])
end
@product_shipment_array.each do |p|
if p['old_pickup_item'] == "true" and p['pickup_item'].to_i==0
@difference = (p['qty_shipped'].to_i)
Product.mark_open_shipment(@difference, p['product_id'])
elsif p['old_pickup_item'] == "false" and p['pickup_item'].to_i==1
@difference = -(p['old_qty_shipped'].to_i)
Product.mark_open_shipment(@difference, p['product_id'])
else
@difference = -(p['old_qty_shipped'].to_i - p['qty_shipped'].to_i)
Product.mark_open_shipment(@difference, p['product_id'])
end
end
respond_with @shipment, :location => shipments_url
end
and in my model I want to declare a model method something like this 在我的模型中,我想声明一个类似这样的模型方法
Class Shipment < ActiveRecord::Base
.
.
.
def update_shipment_attributes
#all business logic
end
end
In the hopes of getting my controller down to something like this or something similar: 希望将我的控制器简化为类似以下内容:
def update
@shipment = Shipment.joins(:products).find(params[:id], :readonly => false)
@shipment.update_attributes(params[:shipment])
@shipment_products = params[:product_shipments]
Shipment.update_shipment_attributes
respond_with @shipment, :location => shipments_url
end
Here are a few approaches you can take to achieve what you want: 您可以采用以下几种方法来实现所需的目标:
accepts_nested_attributes_for
. 研究使用嵌套表单和accepts_nested_attributes_for
。 With nested attributes, your controller edit
method will only need to share one @shipment
instance variable with a nested collection of shipment_products. 使用嵌套属性,您的控制器edit
方法将只需要与嵌套的@shipment
集合共享一个@shipment
实例变量。 update
action only call update_attributes
. 考虑让您的update
操作仅调用update_attributes
。 When you're using nested attributes properly, this should be the the only model call you need because it will implicitly populate the attributes for its shipment_products
. 当你正确使用嵌套的属性,这应该是唯一一款叫你需要的,因为它会隐填充属性为其shipment_products
。 shipment_products
model, use an after_save
callback to mark the open shipments. 在你shipment_products
模型中,使用after_save
回调,以纪念开出货量。 But beware, your shipment_products model should not use the word Product
(capitalized). 但要注意,你的shipment_products模型不应该使用这个词Product
(大写)。 Instead, it should rely on its belongs_to
relation to call product.mark_open_shipment(difference)
. 相反,它应该依靠其belongs_to
关系调用product.mark_open_shipment(difference)
。 difference
should be refactored into an instance method on product_shipments. difference
应重构为product_shipments的实例方法。 The callbacks and update_attributes will all run in one transaction, which will ensure atomicity. 回调和update_attributes都将在一个事务中运行,这将确保原子性。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.