We Love Ruby {Method Chaining}
Tags: ruby, sql
Published: 2022-09-16 15:56:18

A lot of developers love programming in Ruby because of its simplified and almost colloquial nature. For example, a line of Ruby code could read:

```ruby
my_age = 26
puts "Unable to purchase alcohol" unless my_age >= 21
```
You can almost read it in normal English as "Put out to the terminal 'Unable to purchase alcohol' unless my age is greater than or equal to 21."

This was Ruby designer, Yukihiro "Matz" Matsumoto's goal: to make a language that's ultimately easy to use, intuitive to write, and make programmers happy.

I found I love Ruby through how simplified a complex line of code can become with Ruby's style of **method chaining**.

> Method chaining is a convenient way to build up complex queries, which are then lazily executed when needed. Within the chain, a single object is updated and passed from one method to the next, until it's finally transformed into its output value.

> -Jeff Kreeftmeijer

Let's go through a fun example together:

To set the stage, let's say we are a clothing store and we're using Ruby (along with ActiveRecord) to build and access a SQL database. For our framework, we have a one-to-many relationship between each customer and the products he/she purchases -- i.e., a product can only belong to one customer, but a customer can have many products. In our schema (SQL table build), each customer is given a unique ID, and the products table has the customer ID as a foreign key for each product.

Now, we - as the store - want to reward our most $$ lucrative $$ customer (the one who's bought the most products) with a gift as a thank you for all the business. In psuedocode, the way to do this is by counting all the products each customer has purchased and grabbing the customer with the max count. Solution here:

```ruby
id = Customer.joins(:products).group(:id).count
  .max_by { |id,count| count }[0]
Customer.find(id)
```
Let's break this down:

`Customer` is the class we define to represent our customer model.

`joins(:products)` performs a SQL INNER JOIN to compile a list of customers where the respective customer from each product in the products table is returned.

`group(:id)` combines any repeating elements that share the same value in the column defined by the argument. In this case, it combines any customers that share the same unique ID and returns a list of unique customers.

`count` returns a count of elements in a list. But when applied in conjunction with `group`, it provides a count of repeating elements for each unique element. This is returned in a key-value pair for each unique element, like so:
```ruby
# format: {id=>count}
{1=>2, 2=>1, 3=>1, 4=>2} ,
```
where element ID 1 has a count of 2, element ID 2 has a count of 1, and so on.

`max_by { |obj| block }` returns the object with the maximum value based on the `block` condition. In our solution, we're taking each object (`{id,count}`) returned by the `count` method to return the object with the maximum count. The object is returned in array format, `[id, count]` - thus, we tack on `[0]` at the end of our solutionto only grab the ID.

Now that we have the ID of the customer with the most amount of products, we can use the `find(id)` method on the Customer class to return the instance of that customer. And that's it!

It's your turn to experiment and further discover the power of method chaining in Ruby! Happy coding!