Ruby Method Chaining

Linking together multiple Ruby Enumerable Methods in order to maintain concise, readable code

Daisy Chain Flower Crown
Daisy chain (Bellis perennis) CREDIT: RICHARD BLOOM/GETTY IMAGES

One thing that has bothered me as I learn different enumerable methods is that some methods, such as Select or Map, produce new arrays of information. To keep changing or accessing information that these arrays produce, you can assign each method to a variable and call the new variable as you go along, but that can grow cluttered very quickly. This is where Method Chaining (or Daisy Chaining) comes into play. Just like tying together multiple daisies end to end makes a chain, you can string together method after method in Ruby, and get a neat, concise package. This avoids creating variables over and over again, saves time, and allows for much more intuitive and readable code.

Basic Concept

As an example, let’s say we’re working with an array of integers, and we run the select method on this array to find all of the numbers greater than 10.

new_array = [18, 22, 33, 3, 5, 6]new_array.select {|number| number > 10 } => [18, 22, 33]

Awesome. But if we wanted to add all of those numbers together, how would we do that? That array is printed into the terminal, but it isn’t defined anywhere that we could call again. Calling new_array would give the initial array, not the whittled down one we selected over. We could set this equal to a new variable, but instead let’s try to Daisy Chain a sum method onto the end of this select method:

new_array.select {|number| number > 10 }.sum 
=> 73

Linking this method onto the select method allows two operations to be run on this array in one line of code.

Multiple Links In The Chain

Let’s try an example using words in a string. Given this string:

string = "the quick brown fox jumps over the lazy dog"

We can use Method Chaining to capitalize every individual word in this string. Below I’ll add each new method and show the results as each link in the chain is added:

1) string.split 
=> ["the", "quick", "brown", "fox", "jumps", "over", "the", "lazy", "dog"]
2) string.split.map{|word| word.capitalize}
=> ["The", "Quick", "Brown", "Fox", "Jumps", "Over", "The", "Lazy", "Dog"]
3) string.split.map{|word| word.capitalize}.join(" ")
=> "The Quick Brown Fox Jumps Over The Lazy Dog"

Using Daisy Chaining, we were able to split, map, and join this string all in one neat line.

Databases And Many-to-Many Relationships

Discovering this use of Method Chaining has been especially helpful as I have delved into database relationships. While Ruby on Rails utilizes active record to help make data available from many-to-many and one-to-many relationships, Method Chaining adds even more accessibility to information between tables and models.

For this example, the image above represents a basic three model many-to-many relationship. One scientist and one planet make up a mission into space. The scientist and the planet have no direct interaction with each other, but through the mission we can access data for either side.

Let’s say a scientist wants to see what missions he has participated in:

#in the Scientist Model: def mission_method   Mission.all.select{|mission| mission.scientist_id == self.id}end#in the console: @scientist.mission_method => 
[#<Mission:0x00007f989e2dff08
id: 6,
name: "Sleeper",
scientist_id: 5,
planet_id: 6,
created_at: Tue, 23 Mar 2021 20:27:57 UTC +00:00,
updated_at: Tue, 23 Mar 2021 20:27:57 UTC +00:00>,
#<Mission:0x00007f989e2df530
id: 12,
name: "As You Were",
scientist_id: 5,
planet_id: 19,
created_at: Tue, 23 Mar 2021 20:27:57 UTC +00:00,
updated_at: Tue, 23 Mar 2021 20:27:57 UTC +00:00>]

This gives us the two mission instances that this particular scientist has participated in. What if we actually wanted to know the names of the planets involved in these two missions instead of seeing the whole instance? We could write a second method that calls on the mission_method and maps over it to get the planet names, or we could try Daisy Chaining a map method!

#in the Scientist Model:def mission_methodMission.all.select{|mission| mission.scientist_id == self.id}.map{|mission| mission.planet.name}end#in the console:@scientist.mission_method => ["Deep Space Nine", "Beta Quadrant"]

It worked! Now the scientist can call one method and iterate through all of the mission information to get the names of the planets visited.

Photo by Ju Guan on Unsplash

Spacing

These Method Chains can get pretty long. In the example above, the mission_method split into two lines due to length, even though it was one continuous line of code. A way to avoid code being cut off mid-function is to enter each added link in a new line, starting with the “.”

#all code in one continuous line:Mission.all.select{|mission| mission.scientist_id == self.id}.map{|mission| mission.planet.name}.first#same code with each new method entered on its own line:Mission.all.select{|mission| mission.scientist_id == self.id}.map{|mission| mission.planet.name}.first

The nice thing is, either of these configurations will result in the same output. You can space the code out or keep it continuous as desired, and either way you’ll be using a very helpful tool Ruby has developed for us!

Closing Thoughts

Method Chaining/Daisy Chaining can be very helpful when faced with a problem that requires multiple methods to solve. Hopefully Ruby developers can utilize this tool the next time they find the need! It has been incredibly helpful in my understanding of Enumerable method interaction and internal operation, and makes my code look neater (something I always welcome!). Looking forward, I can’t wait to see what problems Method Chaining will help me solve in the future.

Photo by James Harrison on Unsplash

Software Engineer in training at Flatiron School. Passionate about coding, cats, and crossfit

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store