Dynamically show total per page, as I paginate - ruby-on-rails

Rails 3.2
I have the following in my invoices_controller.rb:
def index
#invoices = Invoice.all.paginate(:page => params[:page], per_page: 10)
....
#invoices_total = #invoices.compact.inject(0){ |sum, invoice| sum + invoice.total }
Here's the view (slim):
- if #invoices.any?
tfooter
tr
td colspan="#{checkin_action ? '10' : '9'}" Total
td style='text-align:right'
'$#{number_with_delimiter(#invoices_total)}
This allows me to display the total for each page, in the footer. The problem, is that when I click on next, to move on to the next page, the total does not change. How do I get it to change dynamically with each page change.
Any ideas?

In general, the invoices_total amount should not be changed, no matter what page you are in. The invoices_total can write this way:
#invoices_total = Invoice.count
Or if total is invoics's column,you can:
#invoices_total = Invoice.pluck('total')

I updated my answer.
No need to write this query.
#invoices_total = #invoices.compact.inject(0){ |sum, invoice| sum + invoice.total }
I am giving logic to get the sum of #invoices show in the page.
#Declare a variable to store the sum of the invoices.
<% invoices_total = 0 %>
<% #invoices.each do |invoice|%>
# While looping through your invoices add invoice total to that above variable
<% invoices_total += invoice.total %>
#Rest of your code for show
<% end %>
#Finally the Total Sum like this
<%= invoices_total %>

Related

Is this an efficient way of producing sales reporting / analytics?

I have an app where I receive & ingest daily sales reports from multiple sources. All are structured differently so I store down into my Postgres db in separate tables.
I'm currently doing something like this to iterate over the last 30 days sales for one report source and it seems to work quite nicely. My concern is how efficient & scaleable this will be when I add additional report sources as the way I currently have it structured means I'd have to add and repeat large amounts of the code for each new source.
<% from = Date.today - 30 %> #30 days ago
<% to = Date.today %> #Today
<% step_date = from %>
<% source_one_chart_data = [] %> #Initialise empty array to later pass to JS Chart library
<% begin %>
<% count = #product.sales_source_one.total.where(:report_date => step_date).count %> #check if there are any sales for this product on the current step date
<% if count != 0 %>
<% sale = #product.sum_total_net_by_day(step_date) %>
<% source_one_chart_data.push(sale.to_s) %> #Push sales total to array if sales exist on that date
<% else %>
<% source_one_chart_data.push("0") %> #Otherwise push a zero into array so all 30 days map to a value
<% end %>
<% step_date += 1.day %> #Increase step_date by 1 on each iteration of the loop
<% end while step_date <= to %> #Stop loop when we reach to date
Can anyone offer any guidance on how efficiently bring in additional sales sources without having to repeat code? Also, it would be good if I could change the step from day to week/month/year and have it calculate sales accordingly; so if the sales source is reported daily and the step is week it would sum all values that occur in the step week.
Why do you have all of that code in your view? You should move most of it to your model / controller.
def process_chart_data
from = 1.month.ago.to_date
to = Date.today
step_date = from
chart_data = []
while step_date <= to
sales_total = sales_source_one.total.where(report_date: step_date).count
if sales_total.zero?
chart_data.push(0)
else
sale = sum_total_net_by_day(step_date)
chart_data.push(sale.to_s)
end
step_date += 1
end
return chart_data
end
The above could probably be refactored further, but now if you place it in your Product model then in your controller you can just do:
#product = Product.find(params[:id]) # or whatever
#chart_data = #product.process_chart_data
Then in your view you can use #chart_data.
Moving that code into a method also allows you to update it quicker, lets say I want the user to control how far back records are retrieved:
def process_chart_data(start_date)
from = start_date
...
end
In the controller:
#product = Product.find(params[:id])
#chart_data = #product.process_chart_data(params[:start_date])

How to make partial_counter work with pagination

I have a blogging application in which User has_many posts. I am using pagination with Booststrap. How can I make the partial_count method work with pagination? Currently, the count resets on every page instead of carrying over across pages.
posts_controller.rb
def index
#posts = Post.order("created_at desc").paginate(page: params[:page], :per_page => 12)
end
views/posts/index.html.erb
<%= render #posts %>
<%= will_paginate %>
views/posts/_post.html.erb
<%= post_counter +1%>
<%= post.name %>
The counter works fine on the first page. However, all subsequent pages also start with "1". How can I make subsequent pages start with (number of pages * 12 + 1) instead?
Thanks for your feedback!
Use #posts.offset to get the proper counter initialisation.

Rails - Group using 2 tables and count

I have the following models: students , groups_by_student and groups.
A row of students table is city_id, so I have to show an html table
Total group1 group2 group3
city1 30 10 5 15
city2 2 0 0 2
city3 20 10 10 0
city4 5 0 5 0
city5 10 0 2 8
This is what I did:
groups = Group.find([1,4,6]) #Array of groups id's
total = []
groups.each do |g|
total << Student.joins(:groups_by_students).where(:groups_by_students => {:group_id => g.descendants}).count(:group => :city_id)
end
#I'm using AwesomeNestedSet gem, so g.descendants gives group children.
So now I have an array of 3 hashes that contain the city id as key and the total of students as the value, but now I'm not sure how to present this data in a html table.
How can I iterate per each "total" element? or is there another way of getting this information?
Thanks in advance
Javier
EDIT:
This is the total array
total = [
{city1 =>10, city3 => 10},
{city1 => 5, city3=>10, city4=>5, city5 => 2},
{city1 => 15, city2 => 2}
]
and now I have to place each in a td label inside a html table with the 0 if theres no value for that group.
I've traversed an array of hashes like;
ary.each do |hash| puts "<tr>#{hash.keys} : #{hash.values}</tr>" end
Can you hack that to suit your needs? Am afraid your question doesn't provide a lot to work with.
This is what i did, may be it might help you a little bit: (here the total value is the last column though)
<table>
<% i = 1%>
<% total = 0%>
<% city=""%>
<% 5.times do %>
<tr>
<% city = 'city'+ "#{i}" %>
<% #total.each do |hash| %>
<% if(hash[city].nil?)%>
<% hash[city] = 0 %>
<%end%>
<% total += hash[city].to_i %>
<td><%= hash[city] %></td>
<%end %>
<td> <%= total %></td>
<% total = 0 %>
<% i += 1 %>
</tr>
<%end%>
</table>
Here the row is controlled by city and not the group. Hence i could not find any other way other than a double loop. If you need that total to be printed in the first column and then rest of the information next, then i think you need to display the total first and then loop again and display city values of each group
Also, for this you need to know the number of cities before hand or else we will not know to print '0' for a particular city in a particular group

Rails. Sum a specific attribute on a collection

I have a list of invoices...
#invoices_1_week = Invoice.order("due_date DESC").where("status != 'paid' AND due_date >= ? AND due_date < ?", Date.today, 1.week.from_now)
The invoices model has a total attribute. How can I get a sum of the totals in the #invoice_1_week collection?
I know I can do it in the view like this...
<% week_1_total = 0 %>
<% #invoices_1_week.each do |invoice| %>
<% week_1_total = week_1_total + invoice.total %>
<% end %>
<%= week_1_total %>
But I'm wondering if there is a more Railsy way of doing it.
Here's a Rails way, using ActiveRecord's sum method:
#invoices_1_week.sum("total")
Here are the docs.
You might want to consider using the symbol notation
#invoices_1_week.sum(:total)
or use single quotes
#invoices_1_week.sum('total')
In both cases, the attribute name is immutable.

Order by score through other model

i'm having a users model that has a method score, which actually gets a sum of the score of solved challenges :
def score
self.challenge_level_solutions.inject(0) do |sum, x|
sum + x.challenge_level.points
end
end
Now, i have a Kaminari related controller action like :
def index
#users = User.page(params[:page])
end
My problem is how i would go about displaying the user score in DESC order, that is show the users with a better score about others with a lower score. My view is :
<% #users.each_with_index do |user, index| %>
<%= user.username %> - <%= user.score %>
<br>
<% end %>
and shows :
1. user1 - 0
2. user2 - 0
3. user3 - 2
Any ideas so that it shows properly, with user3 on the first place ?
def index
#users = User.all.sort_by(&:score).reverse
#users = Kaminari.paginate_array(#users).page(params[:page]).per(2)
end
The ruby way to do this is use collection.sort_by
Example:
collection.sort_by{|o|o.score}
Chain .reverse/.reverse! if needed.

Resources