-1

I have an Rails app with a gallery of 6 images. I would like to automatically switch which images are displayed every 24 hours. I have the logic for selecting the images in a rake task, which returns an instance variable of @todays_paper:

namespace :images do
  desc "TODO"
  task next_batch: :environment do
    all_newspapers = Newspaper.all
    filtered_newspapers = all_newspapers.select { |newspaper| newspaper.done == false }
    @todays_paper = filtered_newspapers.first
    @todays_paper.done = true
    @todays_paper.save
    return @todays_paper
  end
end

My question is, how do I pass the @todays_paper instance variable to the controller, and therefore to the view? If I call this in the controller action, even if I'm using Whenever or Sidekiq to run it every 24 hours, it will still run every time the controller action is called, I think.

I don't know whether this is the wrong approach - but I can't think of another way of scheduling this to happen than using a background job. Could I use a Newspaper class method, that could be called perhaps?

tadman
  • 208,517
  • 23
  • 234
  • 262
  • In a Rake task there is no controller and there is no view. Those are only created when there's a *request* received. It's worth noting that `return` in a `task` doesn't do anything, that return value is just ignored. – tadman Jan 20 '23 at 17:43
  • Make use of something like `Date.today.day % Newspaper.count` and you will get each image for a day and will rotate for 6 days – Deepak Mahakale Jan 20 '23 at 17:51
  • Do this in the controller itself – Deepak Mahakale Jan 20 '23 at 17:51
  • What should happen on the seventh day when all six images have been shown? Start the same sequence again? Or will you upload new images manually? – spickermann Jan 21 '23 at 07:20

1 Answers1

0

Option 1: Run a cron job once per day. A popular library for this is clockwork.

You could trigger a cron job via clockwork ... Or not ... That's an implementation detail which is up to you! But basically, you need it to do something like this:

every(1.day, 'Update live newspaper', at: '00:00') do
  current_newspaper = Newspaper.find_by(live: true)
  next_newspaper = Newspaper.find_by(done: false)

  current_newspaper.update_attributes({live: false})
  next_newspaper.update_attributes({live: true, done: true})
end

And then in the controller, just fetch:

@live_newspaper = Newspaper.find_by(live: true)

Note that I've assumed a second attribute (live) on the newspapers table; otherwise there's no way to identify it.

As I said, you could move the above code into a job, or a rake task, or whatever - and invoke it from the scheduler - instead of writing all the code inline. That's up to you.


Option 2: Alternatively, you could do something clever by automatically rotating the newspaper a soon as someone views the website each day.

For example, what if instead of using done as a boolean field, you make it a live_on date field? Then you could do something like this in the controller:

@current_newspaper = Newspaper.find_by(live_on: Date.today) || set_todays_newspaper

...

def set_todays_newspaper
  newspaper = Newspaper.find_by(live_on: nil)
  newspaper.update_attributes({live_on: Date.today})
  newspaper
end
Tom Lord
  • 27,404
  • 4
  • 50
  • 77
  • Thanks very much for this! My issue now seems to be giving the Cronjob (I'm trying out the Whenever gem) my ENV['DATABASE_URL'] to use. I've set this with the Fly.io secrets (I don't think there's another way), but I don't now know how to tell schedule.rb / Whenever how to use my production database. Thanks! – Tom Kitson Jan 27 '23 at 17:28
  • @TomKitson Could you post new/follow-up questions as separate StackOverflow questions? The comments section isn't a good place to address them, as you're only notifying me personally of the question rather than the wider community, and it's not an ideal format to share information. – Tom Lord Jan 30 '23 at 14:09
  • I'm not familiar with `fly.io` (or more broadly how you've chosen to deploy your application), but in general it should be a relatively simple extension to whatever you've done already for the main application. – Tom Lord Jan 30 '23 at 14:11