在Rails控制器中共享方法之间的变量

时间:2013-07-31 22:12:35

标签: ruby-on-rails ruby

我有一个有两种方法的Rails控制器。两种方法都使用了一些相同的变量,我想知道如何将它重构为控制器中某个模型中的一个方法,使它们比现在更容易重用。

class ChartsController < ApplicationController

  before_filter :authenticate_user!, :company_id

  def service_level
    latest_date = Invoice.where(:account_id => @company.accounts).maximum(:invc_date)
    invoices_filter = { :invoices => { :invc_date => (latest_date - 3.months)..latest_date } }

    invoices = Invoice.where({:account_id => @company.accounts}.merge(invoices_filter))
    details = InvoiceDetail.joins(:type).where(:invoice_id => invoices)
    freight_details = details.where(:invoice_detail_types => { :category => 'freight' })

    freight_groups = freight_details.group(:family).select("family, count(distinct package_id), sum(base_charge + discount)")


    vol_data = {}
    spend_data = {}

    @charts = {}

     @charts[:service_analysis] = {
      :vol_data => Hash[freight_groups.map { |row| [InvoiceDetailFamily[row.family].name, row.count.to_i] }],
      :spend_data => Hash[freight_groups.map { |row| [InvoiceDetailFamily[row.family].name, row.sum.to_f] }]
    }

    render partial: 'service_level'
  end

  def weight_summary

    latest_date = Invoice.where(:account_id => @company.accounts).maximum(:invc_date)
    invoices_filter = { :invoices => { :invc_date => (latest_date - 3.months)..latest_date } }

    invoices = Invoice.where({:account_id => @company.accounts}.merge(invoices_filter))
    details = InvoiceDetail.joins(:type).where(:invoice_id => invoices)
    freight_details = details.where(:invoice_detail_types => { :category => 'freight' })
    packages = freight_details.joins(:package, :invoice)



    vol_data = {}
    spend_data = {}
    packages.group(:zone).select("zone, count(distinct package_id), sum(base_charge + discount)").each do |row|
      case row.zone
        when '02'..'08', '002'..'008', '102'..'108', '132'..'138', '202'..'208', '242'..'248', '302'..'308'
          zg = row.zone[-1]
        when '09'..'17', '124'..'126', '224'..'226'
          zg = 'AK/HI/PR'
        else
          zg = 'Import/Export'
      end
      vol_data[zg] = (vol_data[zg] || 0) + row.count.to_i
      spend_data[zg] = (spend_data[zg] || 0) + row.sum.to_f
    end
    @charts = {}

    @charts[:weight_analysis] = {
      :vol_data => Hash[(vol_data.sort_by {|key, value| key.scan(/\d+/)[0].to_i})],
      :spend_data => Hash[(spend_data.sort_by {|key, value| key.scan(/\d+/)[0].to_i})]
    }


    render partial: 'weight_summary'
  end
end

3 个答案:

答案 0 :(得分:3)

我建议使用模型类方法来处理数据。例如

freight_details = details.where(:invoice_detail_types => { :category => 'freight' })

freight_groups = freight_details.group(:family).select("family, count(distinct package_id), sum(base_charge + discount)")


vol_data = {}
spend_data = {}

@charts = {}

 @charts[:service_analysis] = {
  :vol_data => Hash[freight_groups.map { |row| [InvoiceDetailFamily[row.family].name, row.count.to_i] }],
  :spend_data => Hash[freight_groups.map { |row| [InvoiceDetailFamily[row.family].name, row.sum.to_f] }]
}

可以移动到返回charts的模型类方法。以同样的方式,你可以重构你的第二种方法。任何类型的业务逻辑和数据处理都应该在模型中处理

此外,我可以看到控制器中有太多未使用的局部变量。控制器应尽可能薄。

答案 1 :(得分:1)

使用像装饰者这样的概念

module Chart
   extend self
   def service_analysis(freight_groups, freight_groups)

   end
end
class ChartsController < ApplicationController
    @chart = Chart.service_analysis(freight_groups, freight_groups)
end

注意:不要将计算代码放在视图中,它很慢

答案 2 :(得分:1)

如果您决定将其保留在控制器中,请尝试以下操作:

class ChartsController < ApplicationController

  before_filter :authenticate_user!, :company_id
  before_filter :load_data, :only => [:service_level, weight_summary]

  def service_level
    freight_groups = @freight_details.group(:family).select("family, count(distinct package_id), sum(base_charge + discount)")

    @charts = {}
    @charts[:service_analysis] = {
      :vol_data => Hash[freight_groups.map { |row| [InvoiceDetailFamily[row.family].name, row.count.to_i] }],
      :spend_data => Hash[freight_groups.map { |row| [InvoiceDetailFamily[row.family].name, row.sum.to_f] }]
    }

    render partial: 'service_level'
  end

  def weight_summary
    packages = @freight_details.joins(:package, :invoice)

    vol_data = {}
    spend_data = {}

    packages.group(:zone).select("zone, count(distinct package_id), sum(base_charge + discount)").each do |row|
      case row.zone
        when '02'..'08', '002'..'008', '102'..'108', '132'..'138', '202'..'208', '242'..'248', '302'..'308'
          zg = row.zone[-1]
        when '09'..'17', '124'..'126', '224'..'226'
          zg = 'AK/HI/PR'
        else
          zg = 'Import/Export'
      end
      vol_data[zg] = (vol_data[zg] || 0) + row.count.to_i
      spend_data[zg] = (spend_data[zg] || 0) + row.sum.to_f
    end
    @charts = {}

    @charts[:weight_analysis] = {
      :vol_data => Hash[(vol_data.sort_by {|key, value| key.scan(/\d+/)[0].to_i})],
      :spend_data => Hash[(spend_data.sort_by {|key, value| key.scan(/\d+/)[0].to_i})]
    }

    render partial: 'weight_summary'
  end

  private

  def load_data
    latest_date = Invoice.where(:account_id => @company.accounts).maximum(:invc_date)
    invoices_filter = { :invoices => { :invc_date => (latest_date - 3.months)..latest_date } }
    invoices = Invoice.where({:account_id => @company.accounts}.merge(invoices_filter))
    details = InvoiceDetail.joins(:type).where(:invoice_id => invoices)
    @freight_details = details.where(:invoice_detail_types => { :category => 'freight' })
  end

end

两种方法都可以使用实例变量@freight_details。 before_filter只对这两种方法执行load_data方法。

祝你好运!