简体   繁体   English

在has_many:through上使用模型方法简化Rails 3.2控制器

[英]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: 您可以采用以下几种方法来实现所需的目标:

  1. Look into using nested forms and 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实例变量。
  2. Consider having your 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
  3. In your 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM