Untangling Object-Orientation in Ruby for beginners

Shuyi Yu
5 min readJul 6, 2021

--

Photo by Kelly Sikkema on Unsplash

Basic

  1. Defining a class (cheat sheet)
    First thing when starting writing OO programs, defining classes normally comes first. There can be many things inside the class, but there are things that can be considered class definition starters. The code below has the basic syntax for defining a class and has 4 blocks inside :
    1) declaring a class variable @@all to store all the instances in the class.
    2) an instance method to access the @@all variable.
    3) attributes’ setter and getter methods. Try to put all the attributes in attr_reader at the beginning and put it into attr_accessor when necessary.
    4) instance initialization method. If there are default values for some attributes, put them into the parameter area. By doing so, these attributes also become optional.
# the bolden text areas are the areas that need to be changed.class ClassName@@all = []def self.all
@@all
end
attr_reader :attribute1, :attribute2, ..
attr_accessor :attribute_a, :attribute_b, ..
def initialize attribute1, attribute2=default value, ...
@attribute1 = attribute1
@attribute2 = attribute2
attribute_a = attribute_a
.
.
@@all << self
end
end

Side note: when there are limitations on the attributes’ input value, write instance methods to limit them.

2.Class variables(@@var_name) vs instance variable(@var_name) vs normal variable(var_name)
1)Class variables(@@var_name): defined in a class body that can be interacted with without an instance of such class. Class variables are shared among all instances of the class and its subclasses. Can be shared between methods. Static, meaning space for the variable gets allocated for the lifetime of the program, it also gets created when the codes begin to compile.
2)Instance variable(@var_name): defined in a class body but belongs to a specific instance. Its value is not shared between instances of a class or its subclasses. Let say that each instance has variables with the same name but refers to different values. Can be shared between methods.
3)normal variable(var_name): define in a class body, use to store temporary values because it can’t but access anywhere else but where it is defined. Can’t be shared between methods.

Let’s look at the code below for the difference

3.Class method(self.method_name) vs instance method(method_name)
always ask — what is this method used on? On a group(class) or on an individual (one instance). If it is used on a group, for example, get all the instances, count the total number of instances, it is a class method. If it is used on one individual, for example, what’s the attribute(name, age, etc. ) of the instance, it’s an instance method.

ALWAYS REMEMBER TO PUT SELF. IN FRONT OF THE METHOD NAME WHEN DECLARING A CLASS METHOD!!!!

Relationships

when dealing with relationships, it is always a good idea to draw the connection out.

  1. One-to-many
    One-to-many relationship is the basic relationship form between 2 classes, also the foundation of many-to-many relationship.

A mother (an instance of Mother class) has many children, so she will be able to look into the bunch of children(the Child class) and SELECT all the children that are hers. The retrieve method would be something like:

class Motherdef children
Child.all.select{|child| child.mother == self}
end
end

A child only has one mother, so the MOTHER INSTANCE is one of his ATTRIBUTES. Also, all the info about this child should be stored in the Child class. The Child class should look something like this:

class Child@@all = []def self.all
@@all
end
attr_reader :mother, :attribute2, ..def initialize mother, attribute2=default value, ...
@mother = mother
@attribute2 = attribute2
attribute_a = attribute_a
.
.
@@all << self
end
end

2. Many-to-many

One way model:

In many to many relationships, the principles of has-many and belong to relationships remain the same (as the mother/child example). For example, an aquarium shall be able to look into all the exhibitions and SELECT all its exhibitions, one of the exhibition’s ATTRIBUTE shall be the AQUARIUM INSTANCE.

What is special about the many-to-many relationship is the has-many-thru relationship. When jumping classes, meaning when an aquarium wants to look at its fishes, he will always have to look at its exhibitions list first, and then find out what fishes it has. The code in the Aquarium class would look something like this when it wants to know all the fishes it has

class Aquariumdef fishes
Exhibit.all.select{|exhibit| exhibit.aquarium == self}.map{|exhibit| exhibit.fish}
end
end

Since Exhibit class is both a child (of Aquarium class) and a mother (of Fish class), so, it shall have an attribute of an aquarium instance, and a method to get its fishes.

class Exhibit @@all = []def self.all
@@all
end
attr_reader :aquarium, :attribute2, ..def initialize aquarium, attribute2=default value, ...
@aquarium = aquarium
@attribute2 = attribute2
attribute_a = attribute_a
.
.
@@all << self
end
def fish
Fish.all.select{|fish| fish.exhibit == self}
end
end

Join model:

The Join model is the most complicated one, but nothing new here. It is based on the 3 kinds of relationships. Figure out the mother/child relationship, between 2 classes and who is the middle sharing class, the relationship is all set!

Happy coding!

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Shuyi Yu
Shuyi Yu

No responses yet

Write a response