Greg Séguin
Greg Séguin

Reputation: 47

How to refresh an object at a certain time each day in a rails app?

This might be a bit of a basic question, but I searched and wasn't able to find an answer.

In my rails app, I show a random joke on the page whenever the page loads. What I'd actually like to implement is a 'joke of the day', where the same joke displays all day and then refreshes each day at midnight. Can anyone point me in the right direction?

Here's the code I'm currently using to display a random joke:

 class JokesController < ApplicationController
    def index
        @joke = Joke.limit(5).order("RANDOM()").last
    end
 end

And my view:

<div class="col-sm-10 saying">
      <%= @joke.saying.html_safe %> 
</div>

Thanks in advance!

Upvotes: 2

Views: 166

Answers (2)

mtkcs
mtkcs

Reputation: 1716

A better solution I came up with later

Controller

 class JokesController < ApplicationController
    def index
        @joke = Joke.joke_of_the_day
    end
 end

Model

class Joke < ActiveRecord::Base
  def self.joke_of_the_day
    joke = Joke.where(joke_of_the_day: Date.today).first

    # The joke was already picked up
    if joke.present?
      joke

    # Pick a joke for today
    else
      joke = Joke.order("RANDOM()").first
      joke.update(joke_of_the_day: Date.today)
      joke
    end
  end
end

Don't forget to add joke_of_the_day field to your jokes table type date


My original answer

This is not a perfect solution, the algorithm can be improved:

def joke_of_the_day
  count = Joke.count

  # This will make sure the joke is almost unique of this particular
  # date. You can do more complexe calculation to make sure it's
  # unique but you get the basic idea
  sum_of_date = Date.today.year + Date.today.month + Date.today.day

  # loop to make sure the sum_of_date is not greater than the count of jokes
  new_count = loop do
    if sum_of_date >= count
      sum_of_date = sum_of_date / 2
    else
      break (count - sum_of_date)
    end
  end

  Joke.first(new_count).last
end

Upvotes: 1

LolWalid
LolWalid

Reputation: 535

You can add a field today_joke to your joke model then set up a cronjob which will set the joke of the day every day.

You can look at the whenever gem.

First you have to create the method in you model which will randomly choose the "joke of the day" and disable the old one

# app/models/joke.rb
class Joke < ActiveRecord::Base
  # Your stuff

  def self.set_joke_of_the_day
    # if you are using mysql: order("RAND()")
    joke = Joke.order("RANDOM()").limit(1).last 
    joke.update_attributes(today_joke: true)
  end

  def self.disable_joke_of_yesterday
    jokes = Joke.where(today_joke: true)
    jokes.update_attributes(today_joke: false)
  end
end

Then you have to write the task which will update the joke the day every day at midnight (or 1 am or noon, it's your choice)

# lib/tasks/jokes.rake
namespace :joke do
  desc 'Set joke of the day'
  task :today_joke do
    Joke.disable_joke_of_yesterday
    Joke.set_joke_of_the_day
  end
end

# config/whenever
every :day, at: '00:00 am' do
  rake 'joke:today_joke'
end

Finally in your controllers you just have to get the joke of the day

# app/controllers/jokes_controllers.rb
class JokesController < ApplicationController
  def index
    @joke = Joke.where(today_joke: true).last
  end
end

Add the gem whenever in your gemfile

# Gemfile 
gem 'whenever'

Hope this will help you, If you have any questions please let me now.

Upvotes: 0

Related Questions