Output array based on date (sales figures by day) - ruby-on-rails

I have a table with a float called 'cost' and timestamp called'created_at'.
I would like it to output an array with the summing the costs for each particular day in the last month.
Something like:
#newarray = [] #creating the new array
month = Date.today.month # Current Month
year = Date.today.year # Current Year
counter = 1 # First Day of month
31.times do #for each day of the month (max 31)
#adding sales figures for that day
#newarray.push(Order.sum(:cost, :conditions => {:created_at => "#{year}-#{month}-#{counter}"}))
counter = counter + 1 #go onto next day
end
However this doesn't work as all the timestamps have a time as well.
Apologies in advance for the poor title, I can't seem to think of a sensible one.

You should be able to use code like the following:
sales_by_day = Order.sum(:cost,
:group => 'DATE(created_at)',
:conditions => ['DATE(created_at) > ?', 31.days.ago])
(0..30).collect { |d| sales_by_day[d.days.ago.to_date.to_s] || 0 }.reverse
This will sum the order cost by day, then create an array with index 0 being the last 24 hours. It will also take only one query, whereas your example would take 31.
To change the cut off date, replace 31.days.ago with an instance of the Time class. Documentation here: http://ruby-doc.org/core/classes/Time.html
Good luck!

This should work:
(Date.today.beginning_of_month..Date.today.end_of_month).map { |d|
Order.sum(:cost, :conditions => ['created_at >= ? AND created_at < ?', d, d+1])
}
Although I think you should try getting it using a single query, instead of making one for each day.

Related

How to get weekly records on Rails?

I have Payment model with data and amount attributes. Now I need to get all the records for the current week on the page. I want to use some kind of pagination, e.g.: On the first page I get all records for the current week, on the second page - records from the previous week etc.
And on every page I need to get total amount for this week and average amount per day.
So, I have two questions:
How to get all the records for particular week on the page?
How to count amount for this week?
Now everything I've done was array with weeks and amounts
def self.count_by_week
raw_result = group_by_week_and_state.count
# {['2014-12-01-2014-12-07', 'foo'] => 100, ['2014-12-01-2014-12-07', 'bar'] => 100, '...' => '...'}
raw_result.each_with_object({}) do |(k, v), result|
result[k[0]] ||= {}
result[k[0]][k[1]] = v
end
end
def self.group_by_week_and_state
group("#{weekday_query(0)} || \'-\' || #{weekday_query(6)}").group('amount')
end
# build sql part for day offset of week (0 => mon, 6 => sun)
def self.weekday_query(offset)
"to_char(cast(date_trunc(\'week\', created_at) as date) + #{offset}, \'YYYY-MM-DD\')"
end
You could use the groupdate gem to accomplish this.
https://github.com/ankane/groupdate
Once you have successfully grouped your records, it's just too simple to get the sum for each groups.

Allocate daily sales to date created

Im trying to gather all sales made within a week and put each sale in day made. If Moday was two sales, then Monday => {...}, {...} etc
"Monday" would be ruby's date format.
In my db I have 5 sale objects: Two sales on Monday and two on Tuesday.
Controller:
def daily_customer_sale(created)
date_and_id = Sale.where('created_at >= ?', created).pluck(:created_at, :id)
date_and_id.each do |obj|
yield(obj.first, obj.last)
end
end
def daily_sales(created=nil)
sales_by_date = Hash.new(0)
daily_customer_sale(created) do |date, id|
s_date = date.to_date
sales_by_date[s_date] = Sale.find(id) # Seems to return only one object per day
end
return sales_by_date
end
For views:
daily_sales(1.week.ago.to_datetime)
What I get in two dates (correct) in which each data has only one object when it should be two or more per date. Is there something wrong?
You don't need complex logic to do it. Here is a cleaner way
Sale.where('created_at >= ?', created_at).group_by{ |sale| sale.created_at.to_date}
It will return All the sales grouped by day.
key will be date object and for each day there will be sale array containing all of the sales for that day.
If you need string based key you can format it as you like as per below
Sale.where('created_at >= ?', created_at).group_by{ |sale| sale.created_at.to_date.to_s } #default date format
Sale.where('created_at >= ?', created_at).group_by{ |sale| sale.created_at.to_date.strftime("%d/%m/%Y") } #23/09/2016
You can have a look at Group by method

How do I find the sum of donations per month for 24 months?

Having pulled donations from the past two years, I'm trying to derive the sum of those donations per month (a total of 24 sums), storing the keys (each month) and the values (the sum of donations for each month) in an array of hashes.
Here's what I've got so far:
#donations = Gift.between(Date.today - 2.years, Date.today, :field => gift_date)
#donations.each do |donation|
#logic here that puts gift_amount into the right month (of the 24 months)
# and adds it to the previous balance for that month, ending up with 24 keys
# and sum values.
end
How can I do this in Ruby/Rails?
Continuing where #mbratch left off:
donations = Gift.where(:date => (Date.today - 2.years)..Date.today)
Hash[donations.group_by { |d| [d.date.year, d.date.month] }
.map do |year_month, donations|
[year_month, donations.map(&:amount).reduce(:+)]
end]
donation_hash = Hash.new(0)
Gift.where(:gift_date => (Date.today - 2.years)..Date.today).each do |donation|
donation_hash[[donation.gift_date.month, donation.gift_date.year]] += donation.amount
end
This will create a hash with keys of [month, year] and value of total amount donated for that month/year. There are probably a few other suitable ways to create a key which meets the need of your application.

Rails - How to check what the record count of a model 24 hours ago

I want to display the rate of change in the total number of records for a certain model. So I need to know, at any given time, how many there were 24 hours ago, and how many there are now.
It is very likely that a record will be deleted by users, so I can't just use the value of existing records that are older than 24 hours.
Is there a simple way to do this?
Thanks
class Item < ActiveRecord::Base
scope :since, lambda {|time| where("created_at > ?", time) }
scope :during_last, lambda {|time| where("created_at > ?", (Time.now - time)) }
end
Item.since(Time.now - 24.hours).count
Item.since(24.hours.ago).count
Item.during_last(24.hours).count
Well, you could do a count against the column created_at.
def count_rate(model, time=DateTime.now)
current_count = model.count(:conditions => ["created_at < ?", time])
last_24_hours_count = model.count(:conditions => ["created_at < ?", time-24.hours])
current_count - last_24_hours_count
end
This method count the record at a given compared with the last 24 hours.
Well, in case the user has deleted those records back, you would should create another table Rate(date, hour, count) and record every hour by using observer (only after_create).
def after_create
rate = Rate.find_or_initialize_by(Date.today.to_s, Time.now.hour)
rate.increment(:count)
rate.save!
end
In this observer, if it finds the existing record by date and hour, it simply increment the count column. You add the default value to zero on count column as well. Later on, you can query the data from that table by date and hour.

Finding entries belonging to current month (or other months)

I have a model (Expense) that contains fields like 'cost'.
I'd like to iterate through all my expenses to find the sum of the cost for all entries belonging to a particular month.
Is there a way to do it in rails directly?
Expense.find(:all, :conditions => .....)
To get the SUM of costs for the month of a given date:
# date = any day of the month of intrest
Expense.sum(:cost, :conditions => {:created_at =>
(date.beginning_of_month..date.end_of_month)})
To get the sum of costs of all the months:
Expense.sum(:cost,
:group => "EXTRACT(YEAR_MONTH FROM created_at)").each do |y_m, cost_sum|
p "#{y_m}-#{cost_sum}"
end
In the above call, use the conditions option to restrict the result-set to a date range.
sum/group_by:
Expense.find(:all,
:select => "SUM(cost) as cost_sum, MONTH(date) as month, YEAR(date) as year",
:group => "MONTH(date), YEAR(date)" )
Have a look at this beautiful gem: https://github.com/radar/by_star

Resources