Question

I have to output 2 blocks on the same page, each one of them must contain 3 random posts from database.

I have simple model

class Post < ActiveRecord::Base
  scope :random, -> { order('RANDOM()') }
end

I put the ActiveRecord code in application_helper.rb:

module ApplicationHelper
  def random_posts(num = 3)
    posts = Post.uncached do
      Post.random.limit(num)
    end
  end
end

then in layout I use this call twice (Slim template engine used)

= render random_posts

which uses this partial app/views/posts/_post.html.slim

a.btn = post.title

Blocks are filled with 3 random posts from database, but they are the same in each blocks! Why is it so? Each block has to contain different posts.

I've created a repo here with simple demonstration

Was it helpful?

Solution

I got this to work by flipping uncached to cache. I was experimenting on the Post model, but you could probably drop this in your helper just as easily:

class Post < ActiveRecord::Base
  def self.random_posts(n = 3)
    cache do
      random.limit(n)
    end
  end
end

For two calls of the method using uncached, the ActiveRecord log lines are Post Load ... and CACHE ..., but using cache, they are both Post Load.... I really wish I could explain why this works, but it's completely counterintuitive and makes no sense to me.

OTHER TIPS

Forking your code, it seems that the collection Post.random is being cached in Rails in some way. If you add a debugger on the random_posts in ApplicationHelper:

Post.random.map(&:id) 

Will have the same collection every time.

Taken from this blogpost, you could use this as an alternative:

In ApplicationHelper.rb:

def self.random_posts(num = 3)
  ids = Post.pluck(:id).shuffle[0..4]
  Post.where(id: ids)
end
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top