How do I implement "rotating" content on a website?

I’m getting ready to write some generic code to handle “rotation” of
content on our website, an online community featuring authors, books,
etc. What the “rotation” means is that content such as Featured Blogs,
Featured Author, Featured Book, and so on, needs to rotate through a
bunch (e.g. 10+) of DB records, so every time you do a browser
refresh/reload, you see something different and that way each author,
book, blog, etc. gets featured on the website.

How would you handle that? Use cookies to see what the user saw last?
Have the content cached on the server somehow and loop through that?

On an old Java-based community I build, I used a static object on the
web server consisting of an array of content records and an array index
that I incremented for each access to the content; then, I simply looped
through the array for each access till I hit the end, at which point I
reset the array index to 0 in order to start the array from the
beginning on the next access.

Thanks in advance.

On 26 Jul 2007, at 15:06, Ben K. wrote:

Have the content cached on the server somehow and loop through that?
If highlighting a certain item on the front page can be random, I
would suggest a much easier solution (assuming your using MySQL,
don’t know if the other DBMS support this):

@featured_blog = Blog.find(:first, :order => “RAND()”)
@featured_book = Book.find(:first, :order => “RAND()”)

Add conditions if you want to limit the number of records, e.g.
@featured_blog = Blog.find(:first, :conditions => [“updated_at > ?”,
Date.today.last_month], :order => “RAND()”)

This basically translates to “SELECT * FROM blogs LIMIT 1 ORDER BY
RAND()”, it tells MySQL to fetch 1 single random record out of the
resultset.

Best regards

Peter De Berdt

Hi, Peter. This was a great solution! I’ve already implemented this as
an interim solution for the next couple of months since our site hasn’t
officially launched and it’ll be a couple/few months till we begin
getting a lot of traffic.

In the long run, I would like to give everyone precisely equal exposure.
Also, I wonder if there is a better solution for faster performance
using memory versus database calls.

But again, for now, thanks a ton for your help! I have all the
rotations working for now and it was very easy to implement since I
simply had to add the ":order => “RAND()” stuff since I was already
making :find(:first) calls.

Peter De Berdt wrote:

On 26 Jul 2007, at 15:06, Ben K. wrote:

Have the content cached on the server somehow and loop through that?
If highlighting a certain item on the front page can be random, I
would suggest a much easier solution (assuming your using MySQL,
don’t know if the other DBMS support this):

@featured_blog = Blog.find(:first, :order => “RAND()”)
@featured_book = Book.find(:first, :order => “RAND()”)

Add conditions if you want to limit the number of records, e.g.
@featured_blog = Blog.find(:first, :conditions => [“updated_at > ?”,
Date.today.last_month], :order => “RAND()”)

This basically translates to “SELECT * FROM blogs LIMIT 1 ORDER BY
RAND()”, it tells MySQL to fetch 1 single random record out of the
resultset.

Best regards

Peter De Berdt

But again, for now, thanks a ton for your help! I have all the
rotations working for now and it was very easy to implement since I
simply had to add the ":order => “RAND()” stuff since I was already
making :find(:first) calls.

Be careful using RAND() if your dataset is large. You don’t want to
randomly order a million rows only to retrieve one of them. By doing
the
above you’re forcing the database to consider every row in the table
every
time. If you have a lot of rows you may want to do this

  • get total row count from db
  • in ruby get a random number from 0 to the total row count
  • fetch a row ordered by a primary key limit 1 offset that random
    number.

While two queries, it will lower the impact on the database a lot.

anyway, something to keep in mind in case your data gets big.

Thanks, Philip. Another friend of mine also suggested the following
solution. Any thoughts on this solution?


The Rand will work for now. but you could get duplicates, etc.
especially with a small table.

If your content tables implement acts_as_list, they’ll have a sequence
number you can use to select. The current sequence number can be kept in
a cookie. You can treat your content records as a circular queue,
rolling over when they get to the end.

You’ll probably want to cache the max_sequence_number somewhere so you
know when to roll back to the beginning without querying the database
for the max. Maybe in a cookie or in a custom count field. see
#23 Counter Cache Column - RailsCasts The custom count field is better than
a cookie if you will be adding/removing content frequently.

Also, for an equitable distribution, you probably want to have a visitor
start at a random number within the sequence. That way the displays
aren’t over-weighted to the beginning of the sequence if a typical
visitor only does a few refreshes.

Ben,
I wrote a thread yesterday where I’m asking if anyone has created a
‘book’ module and if they somehow ‘piggybacked’ on the Amazon database
and how. Would you be open to my contacting you about this matter?
Thank you,
Kathleen
[email protected]

On Jul 26, 8:06 am, Ben K. [email protected]