title: Rails Group_By Antipattern
body: <p>I frequently encounter a code smell when I use the Enumerable group_by method. Some old code I'm refactoring is a good example</p>
  
  <pre><code>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' =&gt; 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 &gt; 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 &gt; 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
  </code></pre>
  
  <p>Okay so I'm coming through this and I see clearly we need to refactor this report out of an action on the orders controller and into a model of its own to clean up this implementation logic. There's one code smell out, but I still struggle with this orders.group_by hash.</p>
  
  <p>The thing is when I am in the view layer I really want that hash. I need to get summaries from the orders but I need access to the stores. Using the group query method in Activerecord just returns me a relation, which is not as useful as the enumerable group_by hash. I feel like there's a better way to get what I need and reduce a lot of this querying and ruby processing.</p>