【问题标题】:Rails 3.2 Simplify Controller with Model Methods on has_many :throughRails 3.2 使用 has_many 上的模型方法简化控制器:通过
【发布时间】:2012-10-16 12:22:20
【问题描述】:

我见过的大多数关于精简控制器的问题都涉及简单的模型关系。我的问题是,如果您要更新具有多个参数及其关联数组的多对多表单,您如何通过将其全部移动到模型方法来简化任务?例如,看看下面这个大得离谱的控制器。处理这种邪恶的混乱最简单的方法是什么?我不是在寻找一个语法上完美的答案,而是需要就一个方向达成普遍共识。

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

在我的模型中,我想声明一个类似这样的模型方法

Class Shipment < ActiveRecord::Base
  .
  .
  .      
  def update_shipment_attributes
    #all business logic
  end

end

希望让我的控制器降到这样或类似的东西:

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

【问题讨论】:

    标签: ruby-on-rails model controller refactoring ruby-on-rails-3.2


    【解决方案1】:

    您可以采取以下几种方法来实现您想要的目标:

    1. Look into using nested formsaccepts_nested_attributes_for。使用嵌套属性,您的控制器 edit 方法只需要与一个 shipping_products 嵌套集合共享一个 @shipment 实例变量。
    2. 考虑让您的update 操作只调用update_attributes。当您正确使用嵌套属性时,这应该是您需要的唯一模型调用,因为它将隐式填充其shipment_products 的属性。
    3. 在您的shipment_products 模型中,使用after_save 回调来标记未结发货。但请注意,您的 shipping_products 模型不应使用单词 Product(大写)。相反,它应该依靠其belongs_to 关系来调用product.mark_open_shipment(difference)difference 应重构为 product_shipments 上的实例方法。回调和 update_attributes 都将在一个事务中运行,这将确保原子性。

    【讨论】:

    • 我主要只是想重构代码,因为我已经实现了我正在寻找的行为。我正在寻找一个更具体的例子,说明如何将我拥有的业务逻辑移动到它自己的模型方法中。我不知道如何将参数和变量传递给模型方法。
    • 我给出的答案将业务逻辑转移到模型中。如果您绝对必须使用#update_shipment_attributes(不推荐,因为它是一种反模式),那么您应该在实例而不是类上调用它。例如。 @shipment.update_shipment_attributes(attributes)。此外,使用该方法将导致多个事务,这意味着如果第二个事务失败,您的数据将不正确/不一致。考虑改用update_attributes 和回调。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-27
    • 1970-01-01
    • 1970-01-01
    • 2012-06-27
    • 1970-01-01
    相关资源
    最近更新 更多