Delving into Rails has been an extraordinarily enlightening experience. The streamlined nature of creating web applications using a Ruby on Rails framework is quite eye-opening and something I will certainly return to frequently in my programming career.
If you've read any of my previous blog posts, you might remember that I'm a huge movie buff, and I often try to incorporate that into my introductory programming projects. For my first Rails projects, I decided to create a simple web application that allowed users to create their own film awards, which is actually something I do personally quite a bit.
From a broad view, the essential functionality of this web application is very direct.
- User navigates to a homepage.
- User handles a login/signup action.
- Users can then browse awards by year and users, leave comments or create their own awards.
Other than 3rd party authentication through Devise and Omniauth, the basic framework of the application was very straightforward. Rather than going over that, I'd like to zoom in on one specific element of my Rails project because it effectively demonstrates the use of one of the most elastic and indispensable tools available to the Rails developer: the sort_by method. If you are an experienced Rails developer, reading this next section may be maddening, but rest assured there is a happy ending.
In this current project, there are only 3 models: Users, Awards, and Comments (in this case, when you read Awards think "Awards Show". Award encompasses a year and all of the categories and winners). A comment belongs to a User and an Award, and a User can have many comments and Awards can have many comments. As I was building out the web application, it felt natural to give the those navigating the application the ability to sort awards by the most comments.
I knew that when I used Award.all I could access every instance of an Award and its comments, but what I wanted ultimately was something I could iterate over cleanly to produce a webpage with the most commented awards in descending order. So, I needed whatever I was iterating over to already be ordered, or sorted,(wink wink) in a certain way. Here is the Frankenstein's monster of code I ultimately created to deal with this issue.
Firstly, inside my Award model I created a class method: self.most_comments_hash. The purpose of this method is purely to iterate over Award.all, access comments.length and output the number of comments as key in an result hash. At that point, I would push the Award instance related to those comments into an array attached to the key. Ultimately, I wanted to create something that looked like this:
result hash => {
5 => ["Award Instance 1", "Award Instance 2]
}
That was successful, but it didn't solve my sorting problem. As it stood now, the result hash structured above was ordered randomly and iterating over the keys wouldn't produce a properly ordered result. That's where my next class method came into play: self.most_comments_sorted_array. This method iterates over self.most_comments_hash and creates an array output that looks like this:
[[5, ["Award instance 1", "Award Instance 1"], [4, ["Award instance 3", "Award Instance 4"]]
It's a bizarre nested array monstrosity in which the 0 index of the nested arrays is the number of comments and 1 index are all of the award instances with that number comments. This basically accomplished what I wanted. I could iterate over this, grab the number of comments and grab the award instances, but it wasn't easy. This is what I had to code my view to make it all work:
That felt like a huge amount of iteration and coding logic for my view, but it did WORK! However, everything I knew about Rails told me there had to be a better way. There was: the sort_by method.
Rather than creating any class methods, I could do this:
Award.all.sort_by {|obj| obj.comments.length }
This sorted every instance inside Award.all by the number of comments related to the object. The benefit of this was, obviously, significantly less code, but also it precluded the need for my view to be so leaden with its own coding logic as well.
Top comments (0)