rails-how to update attributes based on time/day - ruby-on-rails

How would you update attributes in your database based on the time of day or what day it is. I have three attributes energy, hunger, and happiness that I want to decrease by ten every hour but I don't quite know how to go about doing this. I know there are timestamps in the database but I don't really know how to use them. Also I want to change the players skills every day based on their job. So if you have this job, add 2 to intelligence every day. But I don't know how to add that 2 every day. I would love it if anyone could give me help on this problem. I would greatly appreciate it.

A couple of options:
cronjob: You could setup your cronjob to access the database directly through a SQL script (probably the simplest solution out of all in terms of setup) or go through your rails application first (e.g. in case you need to run additional business logic before updating the database - you mentioned something about updating the database based on the user job). See this post for the latter approach.
Background task: Take a look at Starling/Workling or Backgroundrb. You can use either of these to run a background task that could update your database at regular intervals.

There are two common but fundamentally different ways of achieving this:
During each request, simulate the amount of time which has passed since the last request. If a user makes two requests three hours apart, simulate three hours of time passing by subtracting 30 happiness (10/hour times 3 hours) all at once. This is less resource intensive, but requires a little more thinking on your part. It's not difficult for something as simple as "lower a value by 10 every hour", but more complex interactions are more difficult to model.
Run a cron job which invokes an action in your program every hour, on the hour, to deduct 10 happiness from each account. This is easier conceptually, but involves a lot of overhead if you have many users, especially when some of them are idle for long periods.

Related

Pre-Made ActiveRecord to Optimize Performance / Save Resources

Essentially each time a visitor reaches the application, the controller performs a database query to check what are the most relevant items to show.
Although the items shown vary with time, they are not personally selected for each user.
This means that instead of being calculated each time a visitor comes, it would be better to be system performing a single query every like 10 minutes and store it, to apply on each visit.
What is the best way to apply this idea? I was thinking on cronjobs and maybe store on redis but IDK, some help is appreciated!
There are a number of ways to do this. One way that I've used in the past with success is to have a table in your database that represents the most relevant items and then have a cron job that updates that table.
Fragment caching like #wesley6j recommended isn't a bad way to go either and you can combine the 2 techniques as well if you want.
If you want more detailed suggestions, you can provide some more details about what you are trying to achieve.

Set time to send out HTTP request

Is there a way in Rails to send out a request at a certain time?
I'm using an external credit card charging API, and I want to adjust each monthly subscription based on how many referrals they have (10% each, 10 referrals max). The API has a beta referral system built in, but it doesn't seem to work the way I need it to. Plus, there are just too many unknowns that I'd rather not get into at the moment. I just want to get it up and working, and since my system is fairly simple, I'd rather just do it manually.
There's a billing date for each subscription, and what I want to do is just manually adjust the price of the subscription based on how many active users there are containing the referral code of the user being charged. I'd like to just send out this request to the API just before they're billed. Like sometime around subscription.next_billing_at - 1.minute.
Then just set the subscription.price to price - (price * (User.where(referral_code: current_user_code)).count / 10).
I'm aware this is far from an optimal approach, considering the amount of extra requests being made each month, but since we're small right now, it shouldn't be a problem. Again, it's just a temporary solution so we can get things running now.
There are two options which directly answer your question.
Write a rake task and run it daily with cron via the Whenever gem. If you take this approach, you will have to have the task just load all subscriptions which are due to be billed in the next cycle and update them as required.
Alternatively, use something like Resque-scheduler, which would allow you to run some task at next_billing_at - 1.minute or something.
But if you are small, why not just update the price every time a new referral is created using a callback? Unless there are specific rate or query limits on this API, I doubt a card processor is going to be affected by the traffic you generate. Of course if there are other requirements, like, a referral only applies after a month or something like that, you are going to be stuck with one of the first 2 options, and the Cron + Rake task is probably the best solution in that case.

Regenerating an attribute value on a timed cycle in Rails

Okay, so my User models are able to 'spend' points to give karma (arbitrary points) to other users - each time the User gives a point, their karma_amount is decremented, as you might expect. I'd been originally planning on making it so a user couldn't give karma to another user more than once, but then I thought that it would be cooler to have a finite stock of points that replenishes, by say 1 point every two days.
I'm not quite sure how to accomplish this though - if it was a Ruby script on my machine, sure, but does anybody have any tips having tried something similar in Rails?
My other concern is that if every user has a ticking clock on the live app that'll slow the whole thing down. I guess what I'm asking in a nutshell is: what is the 'Rails-y' way of doing this? Naturally I'd rather find something robust or elegant than just hacking away.
Thanks very much.
You want something that run every period of time (two hours in your example). The operation itself (replenish_karma) could be a simple controller action (be sure to restrict its access, still), then you just need to be sure to call it on a regular basis.
A very simple way could be a simple cron on the server that would initiate a call to that specific route. If you want something inside your rails application, you may want to take a look at background task libs such as delayed_job or resque.

How to have an "action" go off in the future in RoR?

Alright, this is a design question more than anything. I am making a text based game using Ruby on Rails 3, and I'm not sure the best way to implement what I want to do. In the game, the user gets a bunch of goblins, and can tell those goblins what to do. One of the available actions is attack, which as you can assume, means your tribe attacks something else, whether it be an opposing tribe, or a NPC settlement.
If you choose to attack an opposing tribe, then your goblins go off to attack. There is a set point when the battle will commence, (let's say, 10 minutes in the future). Here's the question, what's the best way to implement running the simulation for the battle in exactly 10 (or X) minutes in the future? Because if the simulation is run too soon or too late, then the entire outcome of the battle could be changed by what the opponent does.
(I know it's a little vague, but for those of you who have played Ogame, entire battle outcomes can change if the simulation is run a second too soon or late.)
I was looking at ways to implement having something run at X time in the future (this episode, and the two previous), but it doesn't seem to be tuned toward something that needs to be run precisely at time X. I also looked in to Ruby timers, but there doesn't seem to be a consistent one, like there is in java, nor do they automatically make the data persistent. I was hoping for low coupling too, perhaps using the observer pattern.
So there you have it. If I send my attack, or want to do anything at exactly time X in the future, what's the best way to do this in Ruby on Rails?
Simple answer: Don't
You should save the time (now+10 minutes) in a database and then run a cronjob every minute (or whatever you prefer). This should then evaluate all fights that should be fought at that time.
For best practices on this behaviour see A cron job for rails: best practices?
You could also add a check if a fight can be fought on every request you get. This way you'll get a little bit more randomness when the fight will start exactly and depending on the traffic of your site, this could be like every second. Remember to start a thread to evaluate the fight, depending on the amount of your calculations. Otherwise some users can experience massive lags.
The typical thing to do if you want some event to happen in the future with ruby on rails is to use cron to fire externally (as simon suggested) or use the delayed_job gem and set a job for the future. You can also use rufus-scheduler gem like this:
scheduler.in '10m' do
puts "something happening 10 minutes from now"
end

perform some logic before object is loaded from database

The situation:
The magazine accepts submissions. Once you submit, an editor will schedule your submission for review. Once it has been reviewed, you are no longer allowed to edit it.
So, I have submission in various states. "Draft", "queued", "reviewed", etc. Most of the switches into these various states are triggered by some action, e.g., a submission becomes queued when an editor schedules it. Easy peasey. However, the switch into the "reviewed" state is not triggered by any action, it just happens after a certain datetime has passed.
I have two thoughts on how to accomplish this:
Run a daily/hourly cron job to check up on all the queued submissions and switch them to reviewed if necessary. I dislike this because
I would prefer it to be hourly, so that I can edit my submission up to three hours before a meeting starts
Hourly cron jobs cost money on Heroku, and this application will either never make money or won't make money for months and months to come
Somehow construct a before_load ActiveRecord callback, that will perform some logic on submissions each time they are loaded. "Queued? No? Nevermind. Otherwise, switch it to 'Reviewed' if its meeting is less than three hours away."
I wanted to get people's input on the second idea.
Is that an atrociously smelly way to accomplish this?
If so, can you suggest an awesomer third way?
If 'no' to both of the above, can you give tips on how to perform such logic each time a record is loaded from the database? I would need to always perform some logic before doing a select from the submissions table (which is gearing up to be the most-queried table in the app...)
If there's no good way to accomplish Option Two (or, I hope!, Option Three), I will resort to Option One with a daily cron job. Being able to edit up to a day before a meeting will just have to suffice.
Maybe using after_find, although your performance will sort of suck, same goes if you do something as crazy as before_load, performance would suck, that said money might be more important than performance, if that is so, I would go with the after_find.

Resources