My Profile Photo

Laszlo Balogh


wannabe Software Developer, Engineer, Runner, Photographer and some other things in between...


ActiveRecord association extensions

Hello from after Mod2 project submission!

We just finished our first project within Mod2. As referred to previously, it was the Bike-Share project where we were tasked to develop a web application that utilized a database populated from San Francisco’s bike share service data with stations, trips and weather details and provuded access to content of the base. However access to the databse content wasn’t only through standard routes index, new, show, edit, our implementation also included a dashboard functionality.

It’s been quite an effort and in the process leading up to our project review on Thursday, I learnt a ton! Looking back: it is just simply amazing how much one can learn in a single week. Wow. This alone makes me very excited just thinking about what I can still learn here at Turing

Since again I’ve learnt a lot and just as after previous projects I feel I am that much smarter again, I thought I would share here something that just cliked during this project and what I really think is a cool feature.

Our project relied very heavily on large data sets, which were stored in various tables within our database. In order to get the necessary data out of our database, we had to set up the necessary associations in our models, so that we could utilized the necessary ActiveRecord quiries. That is when I learnt about Association Extension. If you rather explore it and read it for yourself, simply go to the ActiveRecord::Associations::ClassMethods documentation

For reference, this is how our data was structured within our database (used SQL demo from Ondras Zarovi’s site): Bike-Share database table associations

Let’s go through my favorite part here using our stations and trips tables. In this case, each trip had a start_station_id (unique id of the station where the trip started) and an end_station_id (unique id of the station where the trip ended).

We set up the has_many association in our station model to be able to find all trips which started at a particular station through start_trips and to find all trips which ended at a particular station through end_trips.

class Station < ActiveRecord::Base 

  has_many :start_trips,
            class_name: "Trip", 
            foreign_key: "start_station_id"
  has_many :end_trips, 
            class_name: "Trip", 
            foreign_key: "end_station_id"
  
end

Before diving in deeper, a simple example as to how association extension differs from class methods and instance methods.

From coding point of view here is a list where setting up the association extension differs from class methods and instance methods:
1. Definition: within a do...end block attached to the association definition (see example below)
2. Calling: append to the association call, just like any other ActiveRecord methods you would use
3. Reference: since this extension is within a block that belongs to an association, using output of that association is readily avaialble for the extension method, no need to call it (ee code example later in this post)

class Station < ActiveRecord::Base 

  has_many :start_trips, 
            class_name: "Trip", 
            foreign_key: "start_station_id" do
    def say_hello
      "Hello from the association block!"
    end
  end

  def say_hello
    "Hello from the model!"
  end

end  

How would we call these methods? Since our stations and trips tables are already populated with data, for simplicity here, I use Station.first as our station object to call our methods on.

ActiveRecord method call examples - Say Hello

So far not much value add moving say_hello and make it an association extension. Let’s take a look at an actual feature request that we had to implement so we can see how different the code would be in that case.
For this next example, I picked a feature to look up the date when the most trips started at any given station.

class Station < ActiveRecord::Base 

  has_many :start_trips,
            class_name: "Trip",
            foreign_key: "start_station_id" do
    def date_of_highest_count
      group(:start_date).order("count_start_date DESC").count(:start_date).first.first.to_s
    end
  end

  def date_of_highest_count_of_trips_started
    start_trips.group(:start_date).order("count_start_date DESC").count(:start_date).first.first.to_s
  end
    
end

Then once more let’s jump over to our Tux console to see what this implementation offers: ActiveRecord association extension method call example

Though both the date_of_highest_count and date_of_highest_count_of_trips_started methods deliver the same results, but at this point I prefer the association extension implementation for the following reasons:
1. Don’t need to call start_trips when I write the code for the date_of_highest_count method
2. Better separation of functionality: by appending date_of_highest_count to start_trips I know that by calling date_of_highest_count, my search for the date is within the list of trips started at this station.

What do you think? What is your preferred way of implementation?

comments powered by Disqus