Ruby Class vs. Instance Methods: What's the Difference?
There are two types of methods in Ruby, class methods and instance methods.
Instance methods can only be called on instances of a class you initialize.
Class methods are called on classes themselves, not instances.
The difference might sound subtle but whether or not you have to deal with instances will control how to define the method, how you call the method, and what information the method can access in the class.
# class method, we call it on the class itself
Car.get_cars(current_user)
# instance method, we call available_seats on an instance
car = Car.new(miles: 0, seats: 5)
car.available_seats
Let's dive deeper.
Instance Methods in Ruby
Instance methods are called on instances or objects of a class.
For example, we might create a Car
class so we can initialize multiple instances of cars. If we want to be able to call a method on each specific Car instance, we might want to define our method as an instance method.
For the record, most of the methods you define within ActiveRecord will be instance methods.
Here is an example of a class with an instance method.
class Car < ApplicationRecord
belongs_to :owner
has_many :passengers
def initialize(miles:, seats:)
@miles = miles
@seats = seats
end
# This is an instance method
def available_seats
@seats - passengers.count
end
end
Instance methods have the benefit of accessing the instance variables of classes. Because we defined @seats
as an instance variable, our car instance is able to access it in its own instance methods.
A class method wouldn't be able to access the @seats
instance variable of this car.
Class Methods in Ruby
When we want to call a method that doesn't relate to a specific instance, it's best to encapsulate that method as a class method.
An example use case might be, if you want to run a query or fetch all types of cars the meet a certain criteria.
In Ruby on Rails, you might normally write an ActiveRecord query to accomplish this, but for better code organization you should encapsulate complex queries whenever possible into the models they are querying.
Below is an example where we have a query that fetches all instances of our Car
class based on the owner of the car. In order to keep our code DRY and not repeat this query in several places in our codebase, it's best to embed it in our class so we can just reference the class method.
class Car < ApplicationRecord
belongs_to :owner
has_many :passengers
def self.get_cars(owner) # This is a class method
Car.includes(:passengers).where(owner: owner).order(created_at: :desc)
end
end
Now when any part of our application needs to pull this data set, instead of writing out the full query, we can call Car.get_cars(owner)
.
We don't have to worry about updating the query in one place and forgetting to update it everywhere else. Plus, testing this will be much easier.
Connecting the Dots
So now we've defined both class and instance methods. In a real application, this means our class definition would contain both types of methods.
In this case, you need to pay attention, particularly to the name of the method. If it begins with def self
as does def self.get_cars(owner)
that implies this method is called on the class itself and not an instantiated class object.
class Car < ApplicationRecord
belongs_to :owner
has_many :passengers
def initialize(miles:, seats:)
@miles = miles
@seats = seats
end
# This is an instance method
def available_seats
seats - passengers.count
end
def self.get_cars(owner) # This is a class method
Car.includes(:passengers).where(owner: owner).order(created_at: :desc)
end
end
So, what's the difference between these two types of methods? Instance methods are defined inside a particular instance of a class. On the other hand, class methods are defined by the class itself (hence the def self
), and they can only be called on the class itself.
Instance methods are the default, and to create class methods you have to prepend the method name with self.
when defining the class method.
But that's it!
That's the difference between class methods and instance methods, how to define them, and how to call each different method.