Ruby Magic: Blocks

I’ve been using Ruby a lot lately, and recently had to implement a “related” objects feature in Rails. You know, “Related Videos”, “Related Pages”, etc. I decided to sort them by objects that have the most common tags. Try this one-liner:

  #Inside video.rb Model, Related videos
  def related(count=5)
    tags.collect { |tag| tag.videos }.flatten.uniq.sort_by { |video| (video.tags & tags).length }.delete_if { |video| self == video }.reverse[0..count-1]
  end

Let’s try dissecting that:

tags.collect { |tag| tag.videos }

Collects all videos associated with the current object’s tags into an array of arrays (each array representing the slideshows for a particular tag).

.flatten.uniq

Flatten that array (make it a single dimensional array, preserving logical order) and then eliminate duplicates

.sort_by { |video| (video.tags & tags).length }

sort_by sorts the arrays by a particular attribute. So for each video in the array, video.tags & tags gives the intersection of tags for the video under consideration, and the current object’s tags. Because of .length, the sort_by function sorts by the number of such intersecting tags.

.delete_if { |video| self == video }

And, remove self references.

.reverse

Sorting is by default ascending, so reverse the array, and:

[0..count-1]

return only the first n elements.

So, you’d call it by something like video = Video.find(1) and @related_videos = video.related.

The interesting thing is that, I never ever was a programmer given to verbose lengths of code like this. Doing this in any other language would feel so clunky. But in Ruby, it somehow feels natural. Like you can read through the code in your head and have it make perfect sense.

4 responses

  1. Paxil settlement….

    Side effects of paxil cr. Paxil and weight gain. How long will it take paxil to leave the body. Paxil….

  2. Viagra….

    Viagra. Free viagra. Viagra generic….

  3. Could it be @post.related ? @posts is probably an array. 🙂

  4. hi vysnu
    i have been trying to get something similar like this going. thanks for code, but can’t seem to get it to work. but then i am a double n00b when it comes to rails.
    i put the def related (count=5) into my model
    and in my controller @related_posts = @posts.related
    but get a undefined method `related’ error
    what’s goingon here?
    thanks

Leave a Reply

Create a website or blog at WordPress.com