Reputation: 2828
Using Rails 3, and I'm a RoR noob, so this might be simple, but I can't seem to figure it out. What I mean is, I can get it to work, but I can't figure out the best way.
Ok, I've read every question on SO about selecting random records via Rails, and I think the answer is pretty straight forward, for the most part. However, I'm forced to call an acts_as_taggable_on_steroids method before selecting a random record, so my preferred technique doesn't work, since find_tagged_with returns an array.
This is a two-part question. I need to know which of these methods are the best, from a performance standpoint, and also how to prevent duplicate posts from being in the results if this method is called more than once with a different tag.name.
Here are the ways I've tried so far:
def related_posts(tag)
rand_id = rand(Post.find_tagged_with(tag.name).count)
rand_record = Post.find_tagged_with(tag.name, :conditions => [ "posts.id >= ?", rand_id], :limit => 2)
end
def related_posts(tag)
rand_id = rand(Post.find_tagged_with(tag.name).count)
post = Post.find_tagged_with(tag.name, :offset => rand_id, :limit => 2)
end
def related_posts(tag)
post = Post.find_tagged_with(tag.name, :order => 'RAND()', :limit => 2)
end
def related_posts(tag)
posts = Post.find_tagged_with(tag.name)
offset = rand(posts.count)
posts.find(:offset =>offset) #doesn't work since this is an array at this point :(
end
def related_posts(tag)
related = []
posts = Post.find_tagged_with(tag.name)
related << random_post(posts)
related << random_post(posts)
return related
end
def random_post(obj)
rand_id = rand(obj.count)
rand_record = obj[rand_id]
end
Edit: This seems to be the fastest, although I have very little experience performance testing rails apps.
def related_posts(tag)
posts = Post.find_tagged_with(tag.name).sort_by { rand }.slice(0, 2)
end
Whoever happens to answer this question, could you also please explain what exactly is happening? Is it randomising the records and sorting on the database level or something else. Also, what does that typically mean performance-wise with a rails app?
Upvotes: 1
Views: 273
Reputation: 2046
I'll break this line down for ya:
posts = Post.find_tagged_with(tag.name).sort_by { rand }.slice(0, 2)
The first chained call to find_tagged_with sets up the SQL and performs the query. I imagine it's an ActiveRecord::Relation object.
The second, sort_by is a built-in Rails method. So it's not using the database to do the sorting. This could become pricey if you have tens of thousands of records pulled in the first call. More on this here: http://paulsturgess.co.uk/articles/show/85-ruby-on-rails-sort_by-vs-sort
Lastly, the slice(0, 2) is an Array method, cutting up your array of results. There's tons of other ways of doing this, such as .first( 2 ) or [0..2]
Also, here's a detailed Ruby on Rails guide to benchmarking (performance testing each method): http://guides.rubyonrails.org/performance_testing.html
Upvotes: 1