Rails 3.1 - Events based on time - ruby-on-rails

I have an 'Event' model that contains a list of events along with their start time.
When the current time reaches the event start time, I would like to fire some action.
In other words, I want to do something whenever an event starts.
How can I accomplish this in Ruby / Rails ?

There are two ways to deal with this. Either you write a script that checks the Events permanently and triggers some action when the event date is in the past or you use a gem for that. I would suggest you to watch some of the background job screencasts that deal with your problem:
http://railscasts.com/?tag_id=32

Related

Prevent duplicate ActiveJob being scheduled

I have a Rails app that queries an external webservice to update records.
I want to continue polling the web service until the user session expires.
Currently I create an ActiveJob in the show action for the record I want updated.
In the ActiveJob I reschedule it using
self.class.set(wait: 60.seconds).perform_later(record_id)
The problem is that if the user goes to the show action again, it will create another ActiveJob.
Is there anyway to prevent duplicate jobs from being created?
Ideally, there would be a way to search the ActiveJobs to see if one already exists. Something like ActiveJob.find_by(job: JobType, params: record_id). That would allow you to manipulate the jobs before creating a duplicate. I'm going to dig in further and see if that could be created...
The activejob-uniqueness gem is designed to de-dupe jobs. The gem is still relatively new, but it's sponsored by an engineering company (Veeqo) and seems well supported. See also: https://devs.veeqo.com/job-uniqueness-for-activejob/
First set a cookie value when the user visits the show for the first time.
self.class.set(wait: 60.seconds).perform_later(record_id) if cookies[:_aj].nil?
cookies[:_aj] = true
Also maybe create a column in your Record, maybe call it pending_update and set it true whenever you schedule a job to run and set it to false at the end of the scheduled job. That way, even if the user clears the cookies, your program will not create duplicate jobs.

How to get a total number of hours in Ruby on Rails app and show it on the index page?

I am working on an app where the user can log his working hours after he finished his shift. The app is developed in Ruby on Rails 4.I used the scaffold method, so it generated the necessary methods for create, read, update, delete. The fields are hours_worked:number overtime:boolean and date:datetime, for now, I plan to expand it later with more functionality, with user login and some other stuf. The model is empty, I did used the rake db:migrate method. Now I know that you can use the count method, as is shown on the official site for active record. I don't have the idea how to get the total number of hours worked and show it on the index page. Consider that I just started learning Rails. Any suggestions?
Sounds like this is best used with the Timers gem.
https://github.com/celluloid/timers
In your Sessions#new method, you'd want to initialize a variable to keep track of the current time. And then every so often, you'd use one of the methods in the gem to update the current time. You could then subtract the difference.
This is hard to answer without any info on how you are actually logging the info, or seeing any of your code. However if you are just looking for general suggestions you could just save start and stop timestamps and compare them. Or ask the user to input time worked. There are probably a thousand different ways to do this. Please be more specific on what exactly you need help with.

Client Submitted Form to Create a Cron Job on Rails

Okay I decided to improve on what I am asking for help with verse just opening a new question on this. I believe I can accomplish the below if I know of a way that when a client submits a form on my Rails app a cron job is run, where the time for the cron job is selected by the user from a drop down menu. Is there a way to do this, I have been googling around for ideas but haven't found one.
Old Question
I am attempting to develop a system that would allow a user to upload a movie to my site and then have it played back at a certain time. The movies would be continuously streamed, so that at a certain time say after an hour, the next movie in the queue would play. I am wondering is there a gem or script that already does this? Or what is the best way to go about doing it, I thought doing it with jobs like cron or delayed-job, but I don't think that's the most efficient way to do this. Any advice would be appreciated.
p.s. I think a simplier way to explain it is, on YouTube you can queue up videos to be played, so could one do something similiar in rails, this would help towards my problem.
If the user gets to decide the exact time of playback, you could use the rufus-scheduler gem.
Plug in your Time obtained from the user like so:
scheduler = Rufus::Scheduler.start_new
scheduler.at #user_defined_time do
some_method
end
Your some_method could work in tandem with a socket.io wrapper like Juggernaut, which would send a message to the user's browser, which would execute some JS that would fetch the video and play it.
What you could do with this is basically sit around with your browser window open, and when the scheduled time is reached, the browser would fetch the appropriate video and play it.
If you need to implement a video queueing system, you could just enable users to queue up the videos they want to by ID, and then call the next video in the queue via means for a callback function which is triggered when the video has ended. The callback would query the database for the next video in the queue, fetch the video, and play it.
I've used the extremely popular Whenever on projects that rely heavily on scheduled tasks, and it's great. It gives you a nice DSL to define your scheduled tasks instead of having to deal with crontab format. From the README:
Whenever is a Ruby gem that provides a clear syntax for writing and deploying cron jobs.
Example from the README:
every 3.hours do
runner "MyModel.some_process"
rake "my:rake:task"
command "/usr/bin/my_great_command"
end
every 1.day, :at => '4:30 am' do
runner "MyModel.task_to_run_at_four_thirty_in_the_morning"
end
Put your user defined parameters in above query. thats it.
I don't believe you even need to do the background stuff for just front-end scheduling.
Need not to even go for Juggernaut or any Cron Job thingy.
This all can simply be achieved by using JavaScript.
You can either use javascript's setTimeout() and clearTimeout() functions or add a sleep() before your ajax call.
here are the steps:
You load the first movie or just the page.
Make an ajax call within the setTimeout function.
Note: don't forget to assign the setTimeout() to a variable so that you can do clearTimeout(the_variable).
here is the detailed usage: http://www.w3schools.com/js/js_timing.asp
setTimeout works as setTimeout(javascript_statement, milliseconds) ... these milliseconds should be the total time of the current movie or whatever time that's being set by the user subtracted from the current time which gives you milliseconds left to be played.
Send the current movie id in this ajax request, so that on server you can calculate which movie is to be played after the movie just played... by fetching the last movie played with this sent movie-id parameter.
I also believe you'd require some functionality like, only play the next movie when the current movie ends. So basically you can also replace the setTimeout() function for making the Ajax call with the movie-players function. Just make an ajax call to server when the movie-player completes playing the current movie... again sending the current movie-id in the request.
If even after the completion of current movie, you want to wait for the appropriate time to start the movie, you need to make use of periodically_call_remote which sends a ajax requests after a set number of seconds.
And once on server, i.e. in your controller where you handle that ajax request, once you make sure you need to show the movie now, just replace the player container with the partial containing the player and the link to the newmovie with autoplay-on-load set to true.

How to have users create scheduled tasks in rails app deployed on Heroku

I have a rails app deployed on Heroku. I want to add a feature that enables users of the app to set a reminder. I need some way for the app to schedule sending an email at the time specified by the user.
I have found numerous posts referring to using delayed_job for this, but none of the write-ups / tutorials / etc. that I have found directly address what I am trying to accomplish (the descriptions I have found seem more geared towards managing long-running jobs that are to be run "whenever").
Am I on the right track looking at delayed_job for this? If so, can somebody point me towards a tutorial that might help me?
If delayed_job is not quite right for the job, does anybody have a suggestion for how I might approach this?
The most typical way of handling this is to use a cron job. You schedule a job to run every 15 minutes or so and deliver any reminders that come up in that time. Unfortunately, heroku only allows cron jobs to run every hour, which usually isn't often enough.
In this case, I'd use delayedjob and trick it into setting up a recurring task that delivers the notifications as often as necessary. For example, you could create a function that begins by rescheduling itself to run in 10 minutes and then goes on to send any reminders that popped up in the previous 10 minutes.
To view delayedjobs send_at syntax to schedule future jobs check here: https://github.com/tobi/delayed_job/wiki
ADDED after comments:
To send the reminder, you would need to create a function that searches for pending reminders and sends them. For example, let's say you have a model called Reminder (rails 3 syntax cause I like it better):
def self.find_and_send_reminders
reminders = Reminder.where("send_at < ? AND sent = ?", Time.now, false).all
reminders.each do |r|
#the following delayed_job syntax is apparently new, and I haven't tried it. came from the collective_idea fork of delayed_job on github
Notifier.delay.deliver_reminder_email(r)
#I'm not checking to make sure that anything actually sent successfully here, just assuming they did. may want to address this better in your real app
r.update_attributes!(:sent => true)
end
#again using the new syntax, untested. heroku may require the old "send_at" and "send_later" syntax
Reminder.delay(:run_at => 15.minutes.from_now).find_and_send_reminders
end
This syntax assumes you decided to use the single reminder entry for every occurence method. If you decide to use a single entry for all recurring reminders, you could create a field like "last_sent" instead of a boolean for "sent" and use that. Keep in mind these are all just ideas, I haven't actually taken the time to implement anything like this yet so I probably haven't considered all the options/problems.
Check out the runt gem, may be useful for you: http://runt.rubyforge.org/
You can use delayed_job's run_at to schedule at a specific time instead of whenever.
If your application allows the users to change the time of the reminders you need to remember the delayed_job to be able to update it or delete it when required.
Here is more details.
It's good to avoid polling if you can. The worker thread will poll at the database level, you don't want to add polling on top of polling.

Monitor database table for external changes from within Rails application

I'm integrating some non-rails-model tables in my Rails application. Everything works out very nicely, the way I set up the model is:
class Change < ActiveRecord::Base
establish_connection(ActiveRecord::Base.configurations["otherdb_#{RAILS_ENV}"])
set_table_name "change"
end
This way I can use the Change model for all existing records with find etc.
Now I'd like to run some sort of notification, when a record is added to the table. Since the model never gets created via Change.new and Change.save using ActiveRecord::Observer is not an option.
Is there any way I can get some of my Rails code to be executed, whenever a new record is added? I looked at delayed_job but can't quite get my head around, how to set that up. I imagine it evolves around a cron-job, that selects all rows that where created since the job last ran and then calls the respective Rails code for each row.
Update Currently looking at Javan's Whenever, looks like it can solve the 'run rails code from cron part'.
Yeah, you'll either want some sort of background task processor (Delayed::Job is one of the popular ones, or you can fake your own with the Daemon library or similar) or to setup a cronjob that runs on some sort of schedule. If you want to check frequently (every minute, say) I'd recommend the Delayed::Job route, if it's longer (every hour or so) a cron job will do it just fine.
Going the DJ route, you'd need to create a job that would check for new records, process them if there are any, then requeue the job, as each job is marked "completed" when it's finished.
-jon
This is what I finally did: Use Whenever, because it integrates nicely with Capistrano and showed me how to run Rails code from within cron. My missing peace was basically
script/runner -e production 'ChangeObserver.recentchanges'
which is now run every 5 minutes. The recentchanges reads the last looked-at ID from a tmp-file, pulls all new Change records which have a higher ID than that and runs the normal observer code for each record (and saves the highest looked-at ID to the tmp-file, of course).
As usual with monitoring state changes, there are two approaches : polling and notification. You seem to have chose to go the polling way for now (having a cron job look at the state of the database on a regular basis and execute some code if that changed)
You can do the same thing using one of the rails schedulers, there are a few out there (google will find them readily, they have various feature sets, I'll let you choose the one which suits your need if you got that way)
You could also try to go the notification way depending on your database. Some database support both triggers and external process execution or specific notification protocols.
In this case you are notified by the database itself that the table changed. there are many such options for various DBMS in Getting events from a database

Resources