Run Method Certain Time, Day, Year (Ruby) - ruby-on-rails

I am writing a ruby program that will ask a user a to type a message, then a year, month, day and time and then email a message when that time comes. I store that data into a database table. The program should loop until that day comes and then carry out the sending.
Without using a database, I have written the following:
def send_Message(m_to, m_from, m_body, month, day, year, hour, min)
x = 0
t = Time.now
if (t.day == day
&& t.month == month
&& t.year == year
&& t.strftime("%I") == hour
&& t.strftime("%M") == min )
x = x +5
message = #client.account.sms.messages.create(:body => m_body,
:to => m_to,
:from => m_from)
puts message.sid
else
sleep_time = Time.new(year,month,day)
total_sleep = sleep_time - t
sleep(total_sleep)
message = #client.account.sms.messages.create(:body => m_body,
:to => m_to,
:from => m_from)
puts message.sid
end
end
but it only really seems to work with the month, day, year thing, but not time. There are two questions I am seeking an answer to: how can I carry out looping through a database, seeking chronologically messages to send, and with my example code above, how can I use the hour and minute of the day along with the day month and year to send the message.
P.S: I am designing this app on over to rails, where a user/app sends an API request and then the process I mentioned will be carried out.

You have a few approaches:
Look into the gem whenever
gem install whenever
https://github.com/javan/whenever
It doesn't do exactly what you asked but it is much better than running ruby for 6 month's waiting for an email to be sent.
An even better approach is resque https://github.com/defunkt/resque
Then add https://github.com/bvandenbos/resque-scheduler and your solution is very nice without the drag of a million ruby instances waiting to send an email.
Good Luck...
BTW: I made a service to do exactly what you are asking. I have specs and the code. If you want I can get it to you.

Related

Chartkick cumulative chart by date never descending

I have a problem with using a cumulative chart with Chartkick.
At the moment, here is how the chart is built in Ruby:
errors = Error.where(status: 'active')
sum = errors.where('first_occurrence_date <= ?', Time.zone.today - 30.days).count
line_chart errors.group_by_day(:first_occurrence_date, last: 30).count.map { |x,y| { x => (sum += y)} }.reduce({}, :merge)
I have an external service giving me the errors happening on my Rails app, and I collect them using API calls and store them in a database.
The problem is, these errors can have the status Resolved or Active.
On the external platform, I have the possibility to "resolve" the errors when I think I have dealt with the bug. Therefore the status goes from active -> resolved
All these errors have a first occurrence timestamp, on which I'm building my chart. Let's imagine the following scenario:
Monday => 0 errors
Tuesday => 10 errors occurring for the first time
Wednesday => 2 errors (which occurred on tuesday) resolved (active -> resolved) => total of 8 active errors
Thursday => 4 errors occurring for the first time
Friday => 1 error which occurred on Thursday solved, and 1 on Tuesday solved
My graph will have the following values on Wednesday
Monday => 0
Tuesday => 7
Wednesday => 7
Thursday => 10
Friday => 10
(because I only take the errors which have the active status in my chart)
What I would like would be:
Monday => 0
Tuesday => 10
Wednesday => 8
Thursday => 12
Friday =>10
I have thought a moment about how to do, and can't manage to find a solution, anyone has any idea on how to solve this issue ?
Thanks a lot !
I think it is not possible for cumulative data if you only have first occurred timestamp and current status.
If your errors will never be deleted and the only action is resolve (Change from active -> resolved status), you could add a new field, indicate when the error was resolved.
The error will be considered active on a day if they are created before or on that day, and not resolved or resolved after that day. So you query would be:
# Don't filter by status here
errors = Error.where('first_occurrence_date <= ?', Time.zone.today - 30.days)
day_data = (29.days.ago.to_date..Time.zone.today).to_h { |day| [day, 0] }
errors.find_each do |error|
resolved_date = error.resolved_at&.to_date || Time.zone.tomorrow
(error.first_occurrence_date..resolved_date).each do |day|
day_data[day] += 1
end
end
If the error can be reopened/resolved multiple times, can be deleted, or having multiple statuses, this approach will be invalid though. You may consider storing the history amount for each day in a new model via a daily cronjob or something like that, and just query those amounts. For example
Cronjob: run at the end of the day
# first_occurrence_date doesn't matter, we only count the errors still active by the end of the day
DayReport.create(day: Time.zone.today, active_errors_count: Error.where(status: "active").count)
Then simply query for the chart
line_chart DayReport.pluck(:day, :active_errors_count).to_h

Ruby time in Days/hours/minutes between now and the second Tuesday of the month

I am using ruby 2.0.0 an rails 4.0.0.
I have a web service call that is going to run on the 1st of every month.
It's job is to schedule emails to go out on the second Tuesday of the month.
The "Scheduler" web service call has a parameter like this:
?schedule_for_1d&1h&1m
That would schedule the emails to go out 1 day, 1 hour, and 1 minute after the api call is executed.
Right before I make that API call I need to calculate the time, in days, hours, and minutes, between "Time.now" and the second Tuesday of the month, whenever that is.
How can I write that code out and get it in the format of the above "1d&1h&1m"?
def scheduleSecondTuesday
now = Time.now
secondTuesday = 8 + (2-Time.local(now.year,now.month,1).wday) % 7
s = Time.local(now.year,now.month,secondTuesday) - now
dhm = [24*3600,3600,60].inject([]) { |a,b| x,s = s.divmod(b); a<<x }
'?schedule_for_%dd&%dh&%dm' % dhm
end
scheduleSecondTuesday
# => "?schedule_for_5d&9h&48m"
One safety feature included here is that if the task that runs on the 1st of every month fails for some reason and runs some time prior to the second Tuesday or the month, it will still output the correct string.

How would you calculate expiry to update column in rails

I'm trying to figure out the right approach for calculating the remainder days of a user subscription.
For example; user signs up December 25, 2013 for a month and unsubscribed December 29, 2013. Even though he unsubscribed 4 days after subscribing, his subscription should run on PLAN A for the next 27 days (31 day based month).
I'm thinking I would be using the created_at and updated_at of subscription model. So far I got to
**MODEL: subscription.rb
class Subscription < ActiveRecord::Base
before_save :set_expiry_date
def set_expiry_date
#remaining_days = Subscription.calculate(:created_at - Date.today)
Subscription.expiry = '#remaining_days'
Subscription.save
end
end
Something like that but I'm missing something here and this might be an ugly approach. I'm guessing this gives anyone who can help small understanding what I'm after.
I would then run a rake as cron each day at 23:59 that removes 1 (day) from Subscription.expiry number in there and when it finds a 0, it would update something. That's another question though but I placed the stuff about the rake cron so you see where I'm heading with this.
If this were my project, I would take a different approach. I would set subscription expiry to the actual expiry date rather than a decrementing integer. That makes less work for the cron and also feels like good date practice . . . you get the benefit of persisting expiration dates after the expiration, which might be handy for later data analysis. What if there is a bug in your program or your cron fails to run? By persisting the date, you can do some detailed homework or rerun your crons against a specific cohort.
If I needed to know how many days were remaining on the subscription for UI or for API responses, I could call a method on the subscription class that looks something like the remaining_days method below:
def set_expiry_date
#automatically adds a month
#http://ruby-doc.org/stdlib-2.1.0/libdoc/date/rdoc/Date.html#method-i-next_month
Subscription.expiry_date = Subscription.created_at.next_month
Subscription.save
end
def remaining_days
expired? ? 0 : (Date.today - Subscription.expiry_date).to_i
end
def expired?
(Date.today - Subscription.expiry_date).to_i <= 0
end
def expired_today?
Date.today == Subscription.expiry_date
end
Then, my daily cron that does something on expiration (send email beseeching the customer to come back?) would just look for subscriptions where expired_today? == true. My cron would then also ignore subscriptions that expired before today or are yet to expire.

Rails 3 Impressionist indexing by day

I am using the Ruby gem Impressionist. It gives you the ability to look at a count of page hits from a specific date to today date. I'm trying to get the hits from the past 7 days but spit out the number for each day.
#widget.impressionist_count(:start_date=>"2011-01-01") #specify start date only, end date = now
How would I do that? I want 7 days ago but for each day to give me the exact count for that day.
Try this:
#widget.impressionist_count(:start_date => 1.week.ago)
You can get 1 week ago date like this
t = Time.now
lastweek = t - 1.week
and then you can do like this
#widget.impressionist_count(:start_date=>lastweek.strftime('%Y-%m-%d'))
I guess you shold do this in controller, or you can pass just the last week date to the view.
This code works in Rails app cause it uses active_support.
I tried impressionist with mongoid but the filter function didn't work at all in my enviroment.
i hope it does in your app.

Iterating the dates in ruby on rails

I am developing an application for reporting and analytic,where I need to generate data on a daily basis and put it in a CSV.To be more clear, if I take the report today like day one any how I can get the report thats already done, if I get the report tomorrow I should be able to get the data of today,yesterday. If i take after 4 days I should get the report starting from day 1 to day 4.
How it can be done. Looking for heads up
How about this:
today = Date.today
tomorrow = today.next
four_days_ago = 4.days.ago(today)
four_days_later = 4.days.since(today)
(today..(4.days.since(today)).each {|d| puts d}

Resources