Rails Concerns, Helpers, Services and Libraries- A Gist for Beginners
By: Nidhah Fazli
Tags: Ruby on Rails, Beginner

Services and Conventions to Write it

So making the class as heroic as a healthy egg burger should cost them a bit when it comes to Services in Rails. It needs a cherry on top (Oh! I really have seen burgers with cherry on top 😅).

Let the cherry be following conventions:

Service classes possess some encapsulation which keeps discrete pieces of logical structures for your app (to make it discrete we sometimes need a module to help it perform some logics without being repeated. Let’s keep it DRY! But when things stir up we end up with a more cleaner service classes without even getting help from any modules. That saves to be a big talk in big projects 😉).

To bring this encapsulation we thus encourage instance methods rather than class methods. So what are these instance methods and class methods?

A class method provides functionality to a class itself while an instance method provides functionality to an instance of that class. So with instance method a class can have several states depending on the different features it intakes.

Let’s play with some simple examples here since this part can be tricky at any moment. I’m introducing this with a classic example of Vehicle Class (please don’t call me a duffer for setting Vehicle class for a Rails tutorial, trying to keep as simple as possible 🎃).

Class Vehicle

def self.vehicle_act_notice

"You should know some common rules irrespective of the vehicle"

end def fetch_vehicle_type

"This needs vehicle specific features"

end

end >> Vehicle . vehicle_act_notice

=> "You should know some common rules irrespective of the vehicle"



>> Vehicle. fetch_vehicle_type

=> undefined method `from_an_instance' for SayHello:Class





>> v1 = Vehicle.new

>> v1. vehicle_act_notice

=> undefined method ` vehicle_act_notice ' for #<Vehicle:0x0000557920dac930>



>> v1. fetch_vehicle_type

=> "This needs vehicle specific features"

The method with self. serves as the class method which can be received only by the class itself. The other method is called by an instance of the class. Serving a class method is as same as a module method — no state, no behavioural changes. This very thing breaks the encapsulation power and our Service class doesn’t really wants that. So by convention, instance methods are being occupied in Service classes (Surely, there comes instances where we opt for class methods too, but a Service class with mere class methods are obsolete).

So for making each instance’s state, we need some specific features to have different values at each instance. Such features are always initialized while instances are created. Thus it’s convention to write an initialize method in Service classes. Let’s hope back with the example:

Class Vehicle

def initialize(params)

@no_of_wheels = params[:wheels]

@controls = params[:controls]

@type = params[:type]

end def self.vehicle_act_notice

"You should know some common rules irrespective of the vehicle"

end def fetch_vehicle_type

if @no_of_wheels == 4 && @type != 'heavy'

"#{@control} car"

else

"It could be a truck ;)"

end

end

end >> params1 = {wheels: 4, control: "automatic", type: "light"}

>> params2 = {wheels: 4, control: "manual", type: "heavy"} >> v1 = Vehicle.new(params1)

>> v2 = Vehicle.new(params2)

>> v1. fetch_vehicle_type

=> "automatic car"

>> v2. fetch_vehicle_type

=> "It could be a truck ;)"

The instances v1 and v2 possess different state and hence results different when called the same method in effect of the logic.