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 Replies to “Ruby Magic: Blocks”

  1. Pingback: Buy viagra.
  2. 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

    Like

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s