I’m having a tough time deciding how to refactor this method in my controller. The idea is that (in this case) it graphs the users that joined (or were created) in the past two weeks.
You might be wondering why I did the @graph_limit thing, and that is because I always want the day that has the most results to be the tallest bar on my bar chart (which in the view are just created with css by making the height of the <div> using css).
Basically I want to dry it up and… ya know just about improve this method as much as possible:
# Controller
def index
two_weeks_ago = Date.today - 13.days
@users_graphed = User.count(:conditions=>["created_at >= ?", two_weeks_ago], :order => 'DATE(created_at) DESC', :group => ["DATE(created_at)"])
two_weeks_ago.upto(Date.today) do |day|
@graph_limit = 100/@users_graphed.values.max.to_f
@users_graphed[day.to_s] ||= 0
end
end
Also I should mention, that you guys are probably going to rip my code to shreds… so I’m bracing for the outcome.
# View
<% @users_graphed.sort.reverse.each do |user| %>
<li>
<% content_tag :div, :style => "height: #{number_with_precision(user[1] * @graph_limit, :precision => 2)}px; ", :class => "stat_bar" do %>
<%= content_tag(:span, user[1]) unless user[1] == 0 %>
<% end %>
</li>
<% end %>
Ultimately and what my real goal here is to put this into my application controller and be able to chart any models by it’s create_at times. maybe something like tasks.chart_by(2.weeks). How would you guys get this separated out into something I can use throughout the whole app?
I agree with Joseph that your controller here is doing a lot of work that should be done in the model. Any time you’re specifying multiple
findparameters in your controller, ask yourself whether or not that should be in your model instead.You’re doing a lot of iterating here that seems needless. Firstly, You shouldn’t be calculating
@graph_limitinside the loop. You’re recalculating it 14 times, but the value is going to be the same every time. Do that outside the loop.Secondly, that
sort.reversein your view sticks out. You’re already sorting in your finder (:order => 'DATE(created_at) DESC'), and then you’re sorting again in your view and then reversing it? You should instead be asking the database for the values in the final order you want them. Then to make your zero-filling code work you can just reverse it, doingDate.today.downto(two_weeks_ago)instead ofupto.I would say that you should really be doing this all in SQL, but unfortunately (as perhaps you’ve discovered) MySQL makes it difficult to fill in missing days without creating a calendar table to join against.