DRYing Up Your Ruby Code With Modules

One of the fundamental principles in Ruby is DRY: Don’t Repeat Yourself; which makes sense. Why waste time and effort re-writing code when you can simply reuse code you’ve already written? It also means if you ever need to change your code, you only have to change it in one place.

When writing an application you’ll often find there are methods that are the same in two or more of your models. For example, you might have a method on both your Comment and User models that strips spaces from the name attribute before saving the record to the database.

class Comment < ActiveRecord::Base
  before_save :strip_spaces_from_name

  def strip_spaces_from_name
    name = self.name.strip
  end

end

class User < ActiveRecord::Base
  before_save :strip_spaces_from_name

  def strip_spaces_from_name
    name = self.name.stip
  end

end

These methods are exactly the same! We’ve repeated ourselves! How dumb is that? It would make much more sense to store this identical code in a module and then include the module in both the Comment and User classes.

The /lib directory is a great place to store extra modules that can be included in any of your models, controllers etc. In this example, we want to create a new module with an appropriate name like SpaceStripper. Create a file called space_stripper.rb and add the following code to that file:

module SpaceStripper

  before_save :strip_spaces_from_name

  def strip_spaces_from_name
    name = self.name.strip
  end
end

Note – the convention here is to give your file and module the same name. File names are under_scored, module names (constants) should be CamelCased.

Any files in the /lib directory are automatically loaded by Rails so you don’t need to require them in any of your code before calling include. If you wish to add other modules or other classes to a module then usually you’d create a subdirectory in /lib with the same name as your module and add the extra files there. In this case you would have to require these extra files within space_stripper.rb.

To include the methods from a module in any of your other modules or classes, simply use the include:

class User < ActiveRecord::Base
  include SpaceStripper
end

class Comment < ActiveRecord::Base
  include SpaceStripper
end

By including a module into a class, instances of that class inherit all of the module’s methods. However, before_save is not an instance method, it’s a class method. By calling before_save directly in the SpaceStripper module like in the above example, Rails will raise a NoMethodError. Module doesn’t have any method called before_save, that’s a metaclass-method found in ActiveRecord::Base. Instead, we need to change our module a little so that it calls before_save on the class it’s included into when it’s included. We can do this like so:

module SpaceStripper

  def included(base)
    base.send :before_save, :strip_spaces_from_name
  end

  def strip_spaces_from_name
    name = self.name.strip
  end

end

The included method is a callback thats invoked when a module is included into another class or module. The argument (in this case base) is a local variable that represents the class or module you’re including the module in. When we include SpaceStripper into a class like User, we send that class before_save with :strip_spaces_from_name as an argument.

Learn to love modules. By DRYing up your code you’ll write less code, you’ll save yourself time if you ever need to make changes to the code and you’ll earn more coder-karma points.

Written by

Photo of Gavin Morrice
Gavin Morrice

Software engineer based in Scotland

Work with me

Need help with some code?

In my free time, I like to help people improve their code and skills on Codementor.
Contact me on Codementor