In the last article, I wrote about my struggles in converting complex SQL queries into workable code using Ruby & Rails. Sure, I could write the raw SQL if I really wanted to, but as I explained in the article, it’s not the best way to go about it and, let’s face it, working with the built-in Rails stuff just makes things more efficient, and often more fun. To this end, I recently decided to take a step back from working on any of my specific projects, and decided I should focus more on one of the core aspects of Rails that I haven’t fully taken the time to learn just yet.

First, let’s look a little closer at a simple query.

Say you have rails model made up of articles, and you want to find the model instance (database row) of the article with the id of 5. You can easily do that one of two ways:

Article.find(5)

Article.where(id: 5)

Both commands will return the same information, but it may, or may not if you’re more experience at this, surprise you that the results are not identical:

Article.find(5).class

will yield the model name Article, however:

Article.where(id: 5).class

yields the output Article::ActiveRecord_Relation.

Sometimes when I’m trying to solve a problem, I just sort of try combinations. Perhaps you do it too, you run through what you know in your head and can think of to try and figure out how to get done what you want to get done. I had seen reference to this ActiveRecord_Relation in the past, but I hadn’t really paid it any mind. To me it was just something that Rails did but I didn’t fully look into it, and that was a mistake, so the time was now to try and understand what was going on.

Learning about Active Record Relations & Queries

While doing a google search, I happened upon a link to this video at lynda.com. Luckily for me, it was free sampler video so I could watch it without a lynda.com subscription. This article was a nice sort of primer about Active Record and the Active Record Relation concept. Though not a thorough in depth video (because what do you inspect from a teaser video) it did provide some good information on what I would be working with and that there is a noticeable difference that needs to be understood.

A random ask into the twitterspehere led me to a portion of The Odin Project. I’ve known about The Odin Project for a while now, but while I’ve glanced through it, it never seemed like it would be right for my learning style for a variety of reasons. Giving this section specifically on Active Record Queries seemed harmless enough as hopefully I would learn something, and thankfully for me, it turns out I learned quite a bit (though I’m still digesting, processing, and learning to use all of it).

This page on the The Odin Project was helpful, but what really provided the most help was pointing me to the Rails Guide on querying with Active Record.

Obviously, I had seen the guide before. If you work on Rails and are looking to solve an issue, your first web search result is often going to be a link to a Rails Guide. Usually when I end up at a Rails Guide page, I’m looking for something specific, like the correct way to do something in a migration or the correct format for a scope. In the past, I had tried to work my way through some of the Guides and never had much success (specifically the one on the built-in email functionality) in understanding them or feeling overwhelmed. This time though that didn’t happen.

The Odin Project takes you on a round about journey through the Guide. Start with the first part, then skip ahead, then come back to another section, and around you go, reading most, but not all, of the Rails Guide. Interestingly, even though The Odin Project discusses the N+1 query problem and eager loading (which is so awesome by the way), it doesn’t tell you to read section 13 of the Rails Guide which is about eager loading. I can’t explain the reason or the why fully, but this time as I read through it, things started to click for me. Simple things like .where were now making sense. Writing a multi-table join, which I can do in a snap in SQL, but I had always had trouble figuring out in Rails now made sense once I read the section on .joins. I could go on generally about the things I learned but I do want to show that the general learning led to some concrete breakthroughs in a project.

The Power of Pluck

Before I started working on Rails, I never had much use for plucking. I didn’t play the banjo, I don’t care that much about my eyebrows, and let’s face it, if you know me, the idea of me even being in a situation where I would pluck a chicken is down right laughable, but Rails changed all that for me. I love plucking

In Rails pluck does something pretty simple that I’m betting can be pretty powerful, in a variety of ways. After reading the section on pluck, I immediately thought of one place where I might use it, so I thought I’d give it a try.

One of the more important things when following sports is determining who won and who lost (or for some of you, those who didn’t win). Usually you look at the standings for a sports league, you see a teams record and their winning percentage. In theory a pretty easy thing to calculate, so one of the first methods I did build within my Rails application was a method for determining a teams record (with testing and every thing), and the original method looked so:

  def record
    wins = self.participants.win.count
    losses = self.participants.loss.count
    total = self.participants.count
    {record: "#{wins}-#{losses}", pct: (wins/total.to_f).round(3)}
  end

Now that did work fine, but with my new understanding of pluck, and a little Ruby magic, I realized that I could do the same thing with only one call to the participants, like so:

  def record_version_two
    outcomes = self.participants.pluck(:winloss)
    wins = outcomes.count("W")
    losses = outcomes.length - wins
    {record: "#{wins}-#{losses}", pct: (wins/outcomes.length.to_f).round(3)}
  end

Now, with my application so small and only me, I doubt that makes much of a visible performance difference, but the pluck version does seem to run slightly faster based on the rails console indication of the ms for each step, and in the long run, as the application has more data (and more visitors) that might be pretty important. I realize there’s probably some refactoring that could be done to each method, but it was nice just to do that little bit of work.

Putting where to good use - getting opponents

With my database set up, finding an opponent for a given participant would involve joining to the table itself (the participant table) on a game_id and excluding the existing team. For a long while now, I had been unsure how to figure this out. A big part of that was not really understanding the query methods. A smaller, yet no less significant, part of the issue was not fully grasping that I couldn’t use a scope to do it all at once. I did try writing a self-join within the participant model, but I could not get that to work. That would be ideal at some point, but after my study of the guide on queries, I was able to write a method that, with testing, worked.

As I already had a complex participant_spec.rb file working with a smidgen of test data, I created a secondary participant_queries_spec.rb file that I could write model tests on using the larger dump of data I had obtained and could put into my test data using before { system 'psql -d nba_test -f spec/dumps/query_data_source.sql' }. Using the rails console, I isolated the game_id of the last record in the participant model (Participant.last) and then identified the other team playing in the game and wrote the test thusly:

        scenario "Finding the opponent works" do
                expect(Participant.last.opponent).to eq "Lakers"
        end

For now, I wanted the method to return what I refer to as the nickname of the team. I could use a different attribute of the team later, but this served my purpose. Using my new found understanding of .where, I was able to fashion the instance method that worked rather quickly. It didn’t work on the first try but it did take less than five. The method I ended up with was:

  def opponent
          opponent = Participant.where("game_id =? and team_id != ?", game, team).first
          opponent.team.nickname
  end

The kicker for me was having to put first at the end, because I am still learning. I should have realized that the portion before first, even though it only returns one result, is still an ActiveRecord_Relation. Sure, the relation does contain one instance of the participant model, but it’s not the same thing. If you call nickname on the relation itself, you’ll get an error similar to this one: undefined method nickname’ for #`. You have to access the insides of the relation, even if there is only one instance inside, to be able to use the nickname attribute which belongs to participant itself, and not the relation containing the participant instance you found.

So even though I had learned, it was obvious i was still going to need to learn more, but I am now more comfortable that I could write efficient and useful methods, both on instances and classes so that I could access the data to get my nba application to a ready state to launch. Of course, I’d still have to figure out deployment on digital ocean and how to schedule a daily update, plus I haven’t taken some other things into consideration, but after the two days spent going over these learning materials, I felt like I had moved more forward in my goal to becoming a good developer, than I had in a while since most of my work previously was very project focused.

Hopefully this reminder to myself that learning the foundation first is almost always helpful when focusing on the specifics of a given project sticks with me and finds some use in your work as well, whatever work that may be.