Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/55.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails Rails组_(按反模式)_Ruby On Rails_Activerecord_Group By - Fatal编程技术网

Ruby on rails Rails组_(按反模式)

Ruby on rails Rails组_(按反模式),ruby-on-rails,activerecord,group-by,Ruby On Rails,Activerecord,Group By,在使用可枚举的group_by方法时,我经常遇到代码气味。我正在重构的一些旧代码就是一个很好的例子 def punctuality_report params[:date] ? @date = Date.strptime(params[:date], "%m/%d/%Y") : @date = Date.today params[:through] ? @through = Date.strptime(params[:through], "%m/%d/%Y") : @through =

在使用可枚举的group_by方法时,我经常遇到代码气味。我正在重构的一些旧代码就是一个很好的例子

def punctuality_report
  params[:date] ? @date = Date.strptime(params[:date], "%m/%d/%Y") : @date = Date.today
  params[:through] ? @through = Date.strptime(params[:through], "%m/%d/%Y") : @through = @date + 1
  time_range = @date.to_formatted_s(:db)..@through.to_formatted_s(:db)
  @orders = Order.daily.includes(:store).where('orders.created_at' => time_range).group_by{|o| o.store}
  @orders.each_key.each do |s|
    eval "@s#{s.id}_early = @orders[s].collect{|o| o if o.early?}.compact"
    eval "@s#{s.id}_avg_early = @s#{s.id}_early.count > 0 ? @s#{s.id}_early.collect{|o| o.earliness}.sum / @s#{s.id}_early.count : '0'"         
    eval "@s#{s.id}_late = @orders[s].collect{|o| o if o.late?}.compact"
    eval "@s#{s.id}_avg_late =  @s#{s.id}_late.count > 0 ? @s#{s.id}_late.collect{|o| o.lateness}.sum / @s#{s.id}_late.count : '0'"         
    eval "@s#{s.id}_on_time = @orders[s] - (@s#{s.id}_early | @s#{s.id}_late)"
  end
end
好的,我已经讲完了,我清楚地看到,我们需要将这个报告从orders控制器上的一个动作重构成一个模型,以清理这个实现逻辑。有一个代码嗅出了味道,但我仍然在努力处理这个命令。按散列分组


问题是,当我在视图层时,我真的想要那个散列。我需要从订单中获取摘要,但我需要访问商店。在Activerecord中使用group query方法只会返回一个关系,它不如可枚举的group_by hash有用。我觉得有更好的方法来获得我需要的东西,并减少大量的查询和ruby处理。

我真的不认为GroupBy方法有什么问题。我确实看到了过度使用eval的问题,尽管[-;eval是一种比groupby强得多的代码气味(IMHO)

话虽如此,我确实看到了重构的一些其他方面:

# Consider this refactor:

def punctuality_report
  # I find this slightly more readable
  @date = (params[:date]) ? Date.parse(params[:date]) : Date.today
  @through = (params[:through]) ? Date.parse(params[:through]) : @date + 1.day

  # the .in_time_range(range) method can be defined as a scope on the Order model, and you can
  # get rid of that logic here
  # 
  @orders = Order.daily.includes(:store).in_time_range(@date, @through).group_by(&:store)

end

class Order < ActiveRecord::Base

  scope :in_time_range, lambda { |date, through| where('orders.created_at' => (date..through)) }

  # It looks like you already know how to collect the orders for your needs... ie Order#early, etc

end

# Now, consider in your views the ability to do this:
@orders.each do |store, orders|
  # the orders now are the orders that met the above qualifications for the store
  orders.early
  Order.average_of_orders(orders.early)
  orders.late
  Order.average_of_orders(orders.late)
  orders.on_time    
end
>代码>考虑这个重构: def准时性报告 #我觉得这更具可读性 @date=(params[:date])?date.parse(params[:date]):date.today @通过=(参数[:到])?Date.parse(参数[:到]):@Date+1.day #.in_time_range(range)方法可以定义为订单模型上的范围,您可以 #在这里摆脱这种逻辑 # @订单=订单。每日。包括(:存储)。在时间范围内(@date,@to)。分组依据(&:store) 结束 类顺序(date..to))} #看起来你已经知道如何根据自己的需要收集订单了 结束 现在,在你的观点中考虑这样做的能力: @订单。每个do |存储,订单| #现在的订单是符合商店上述条件的订单 早早下单 订单。订单的平均数量(订单。早期) 晚点 订单。平均订单数量(订单延迟) 准时订购 结束
我真的不认为groupby方法有什么问题。我确实看到了过度使用eval的问题,尽管[-;eval是一种比groupby强烈得多的代码气味(IMHO)

话虽如此,我确实看到了重构的一些其他方面:

# Consider this refactor:

def punctuality_report
  # I find this slightly more readable
  @date = (params[:date]) ? Date.parse(params[:date]) : Date.today
  @through = (params[:through]) ? Date.parse(params[:through]) : @date + 1.day

  # the .in_time_range(range) method can be defined as a scope on the Order model, and you can
  # get rid of that logic here
  # 
  @orders = Order.daily.includes(:store).in_time_range(@date, @through).group_by(&:store)

end

class Order < ActiveRecord::Base

  scope :in_time_range, lambda { |date, through| where('orders.created_at' => (date..through)) }

  # It looks like you already know how to collect the orders for your needs... ie Order#early, etc

end

# Now, consider in your views the ability to do this:
@orders.each do |store, orders|
  # the orders now are the orders that met the above qualifications for the store
  orders.early
  Order.average_of_orders(orders.early)
  orders.late
  Order.average_of_orders(orders.late)
  orders.on_time    
end
>代码>考虑这个重构: def准时性报告 #我觉得这更具可读性 @date=(params[:date])?date.parse(params[:date]):date.today @通过=(参数[:到])?Date.parse(参数[:到]):@Date+1.day #.in_time_range(range)方法可以定义为订单模型上的范围,您可以 #在这里摆脱这种逻辑 # @订单=订单。每日。包括(:存储)。在时间范围内(@date,@to)。分组依据(&:store) 结束 类顺序(date..to))} #看起来你已经知道如何根据自己的需要收集订单了 结束 现在,在你的观点中考虑这样做的能力: @订单。每个do |存储,订单| #现在的订单是符合商店上述条件的订单 早早下单 订单。订单的平均数量(订单。早期) 晚点 订单。平均订单数量(订单延迟) 准时订购 结束
如果使用得当,我认为group_by是一个非常有效的工具。我在一个cron作业中使用了一个方法,该方法使用了一些嵌套的group_by语句,我确信这会导致显著的速度减慢。我花了2个小时重写该方法以摆脱group_by,运行时间从1小时8分钟增加到1小时5分钟。哈值得付出努力

另一方面,这段代码有一些严重的问题。那些三元运算符实际上让我大笑,而eval语句就是邪恶的。他们不仅使用eval,而且使用得很糟糕。调用eval非常慢,没有理由所有5个eval语句都不能合并成一个


也就是说,在这个方法中,即使是一个eval语句也太多了。我确信eval有一个时间和地点,但我的代码中从来都不需要它。根据我的一般经验,几乎所有对eval的调用都可以用send来代替,这会更快更安全。

我认为如果使用得当,groupby是一个非常有效的工具。我有一个方法我在一个cron作业中使用了一些嵌套的group_by语句,我确信这会导致显著的速度减慢。我花了2个小时重写该方法以摆脱group_by,运行时间从1小时8分钟变为1小时5分钟。这几乎不值得

另一方面,这段代码有一些严重的问题。那些三元运算符实际上让我大笑,而eval语句就是邪恶的。他们不仅使用eval,而且使用得很糟糕。调用eval非常慢,没有理由所有5个eval语句都不能合并成一个

也就是说,在这个方法中,即使是一个eval语句也太多了。我确信eval有一个时间和地点,但我的代码中从来没有需要它。根据我的一般经验,几乎所有对eval的调用都可以用send代替,这会更快更安全。

我的尝试:

def punctuality_report
  @date    = params[:date]    ? Date.strptime(params[:date], "%m/%d/%Y")    : Date.today
  @through = params[:through] ? Date.strptime(params[:through], "%m/%d/%Y") : @date + 1

  time_range = @date.to_formatted_s(:db)..@through.to_formatted_s(:db)

  @orders = Order.daily.includes(:store).where('orders.created_at' => time_range).group_by{|o| o.store}

  @orders.each_key.each do |s|
    all_early = @orders[s].collect{|o| o if o.early?}.compact
    all_late  = @orders[s].collect{|o| o if o.late?}.compact
    self.instance_variable_set("@s#{s.id}_early", all_early)   
    self.instance_variable_set("@s#{s.id}_avg_early", all_early.count > 0 ? all_early.collect{|o| o.earliness}.sum / all_early.count : 0)         
    self.instance_variable_set("@s#{s.id}_late", all_late) 
    self.instance_variable_set("@s#{s.id}_avg_late", all_late.count > 0 ? all_late.collect{|o| o.lateness}.sum / all_late.count : 0)         
    self.instance_variable_set("@s#{s.id}_on_time", @orders[s] - (all_early | all_late) )
  end
end
简而言之:在
eval
部分中,只添加了实例变量,我们可以使用
instance\u variable\u get
instance\u variable\u set
来代替。几乎所有
eval
的出现都可以避免,但我也相信
eval
有时会非常有用和强大

代码更清楚地表达了它的意图:它将添加一组实例变量,这些变量一看到就立即可见

<>我绝对不认为使用<代码> GROPY由成为代码嗅觉。

< P>我的尝试:

def punctuality_report
  @date    = params[:date]    ? Date.strptime(params[:date], "%m/%d/%Y")    : Date.today
  @through = params[:through] ? Date.strptime(params[:through], "%m/%d/%Y") : @date + 1

  time_range = @date.to_formatted_s(:db)..@through.to_formatted_s(:db)

  @orders = Order.daily.includes(:store).where('orders.created_at' => time_range).group_by{|o| o.store}

  @orders.each_key.each do |s|
    all_early = @orders[s].collect{|o| o if o.early?}.compact
    all_late  = @orders[s].collect{|o| o if o.late?}.compact
    self.instance_variable_set("@s#{s.id}_early", all_early)   
    self.instance_variable_set("@s#{s.id}_avg_early", all_early.count > 0 ? all_early.collect{|o| o.earliness}.sum / all_early.count : 0)         
    self.instance_variable_set("@s#{s.id}_late", all_late) 
    self.instance_variable_set("@s#{s.id}_avg_late", all_late.count > 0 ? all_late.collect{|o| o.lateness}.sum / all_late.count : 0)         
    self.instance_variable_set("@s#{s.id}_on_time", @orders[s] - (all_early | all_late) )
  end
end
简而言之:在
eval
部分中,只添加了实例变量,我们可以使用
instance\u variable\u get
instance\u variable\u set
inst