- Read Tutorial
- Watch Guide Video
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.