Overview of Private vs Public Methods in Ruby
This is going to be a fun episode, as we are going to talk about sending an sms message. Also, we are going to be learning about private and public methods.
Guide Tasks
  • Read Tutorial
  • Watch Guide Video
Video locked
This video is viewable to users with a Bottega Bootcamp license

This is going to be a fun episode, as we are going to talk about sending an sms message. Also, we are going to be learning about how Ruby works with private and public methods.

Now, I'll go back to the ApiConnector class and create a class called SmsConnector that inherits from the ApiConnector class. In this class, I create a method called send_sms. Inside this method, I'm going to place code that will run a script that contacts an API that I created, it will look like this:

class SmsConnector < ApiConnector
  def send_sms
    `curl -X POST -d "notification[title]=#{@title}" -d "notification[url]=http://edutechional-resty.herokuapp.com/posts/1" "#{@url}"`
  end
end

This method will send a title and link to an API, which will in turn send a SMS message. You don't have to worry about the code that will be handling the actual SMS sending, which is part of the beauty of the implementation.

If you notice, the URL in the method and the URL value we are passing are different. Essentially the app we're sending the API request to will send the title and the devcamp.com URL to my phone. This is cool because we don't have any logic inside our class to send the SMS message. Rather, we are simply processing the data and then connecting to a third-party app that manages SMS communication. This type of application workflow is called service-based architecture.

Now we can instantiate the SmsConnector class and call the send_sms message.

sms = SmsConnector.new(title: "Hey there!", url: "http://edutechional-smsy.herokuapp.com/notifications")
sms.send_sms

Running this code will contact the SMS API and send the message.

Private vs Public Methods

Now, coming back to the types of methods provided by classes, the send_sms method is a public method. This means that anyone working our class can communicate with this method. This may not seem like a big deal if you are working on an application that no one else is working on. However if you build an API or code library it's vital that you your public methods represent elements of functionality that you actually want other developers to use.

Public methods should rarely, if ever, be altered. This is because other developers may be relying on your public methods to be consistent. And a change to a public method may break components of their programs. Imagine if you developed the Google Maps API and you built a public method called get_coordinates, but out of the blue you altered the method and reversed the order of the coordinates. All of the applications relying on your method would have their maps literally reversed. Obviously this would upset developers.

So if you can't change public methods how can you work on a production application? That's where private methods come in. Private methods should never be called by outside services and should only be available within the class that's using them. This means that you can alter the behavior of your private methods (assuming that these changes don't have a domino effect and alter the public methods that they may be called from).

So what exactly is a private method? A private method is a method that is only accessed by the class that it is contained in.

devCamp Note: Ruby is so flexible that it allows private methods to be called, however it is considered bad programming practice. If a private method really needs to be called by an outside service either: it should be a public method, or there is a design problem with the application that's forcing this behavior.

Private Method Code Example

To see what a private method looks like let's take a look at a real world Ruby on Rails project that I built.

class InventoriesController < ApplicationController
  # Public methods not shown for brevity

  private

    def set_inventory
      @inventory = Inventory.find(params[:id])
    end

    def inventory_params
      params.require(:inventory).permit(:title, :qty, :ticket_id)
    end
end

As you can see, in Ruby we designate private methods by using the private word above the list of methods. Usually, private methods are placed at the end of the file after all the public methods. Both private methods shown here provide functionality specific to the InventoriesController class, and to no other.

Going back to our code example. If we go back to the ApiConnector class and add a private method like this:

class ApiConnector
  def initialize(title:, url:)
    @title = title
    @url = url
    secret_method
  end

  private

    def secret_method
      puts "A secret message from the parent class"
    end
end

api = ApiConnector.new(title: "My Title", url: "https://devcamp.com")

Notice how we're calling this method from the inside of the initialize method of the ApiConnector? If we run this code it will give the following output:

A secret message from the parent class

Now child classes have access to methods in the parent class right? Well not always. If we remove the secret_method method from the initialize method in ApiConnector and try to call it from our SmsConnector child class like this:

class ApiConnector
  def initialize(title:, url:)
    @title = title
    @url = url
  end

  private

    def secret_method
      puts "A secret message from the parent class"
    end
end

class SmsConnector < ApiConnector
  def send_sms
    `curl -X POST -d "notification[title]=#{@title}" -d "notification[url]=http://edutechional-resty.herokuapp.com/posts/1" "#{@url}"`
  end
end

sms = SmsConnector.new(title: "My Title", description: "My Great Description", url: "http://edutechional-resty.herokuapp.com/notifications")
sms.secret_method

The output of the program will be:

api_connector.rb:21:in `<main>': private method `secret_method' called for #<SmsConnector:0x007f99e2823718> (NoMethodError)

This is because the SmsConnector class only has access to the public methods from the parent class. The private methods are, by their nature, private. This means that they should only be accessed by the class that they are defined in.

So a good rule of thumb is to create private methods when they should not be used outside the class and public methods when they have to be available throughout the application or by outside services.

devCamp Note: All methods in Ruby are public by default, so you don't have to explicitly declare them as public.

Ruby also has another type of method status called protected, however it is rarely used. So, we won't worry about it for now.