Rails concern and service object to refactor

Reading time ~1 minute

Rails concern

This is part of the code in Launch School 301 course. And in the code below, it shows how to extract the duplicate code in different module to ActiveSupport::Concern. But there are more than one way to refactor the code. DHH in the signal v. Noise wrote an article to introduce the concerns :

Different models in your Rails application will often share a set of cross-cutting concerns. In Basecamp, we have almost forty such concerns with names like Trashable, Searchable, Visible, Movable, Taggable.

Ryan Bates of Railscasts wrote an article to talk to people not to use concern. He encourage people to use Service Object.

  module Sluggable
    extend ActiveSupport::Concern
    included do
      before_save :generate_slug!
      class_attribute :slug_column
    end

    def to_param
      self.slug
    end

    def generate_slug!
      the_slug = to_slug(self.send(self.class.slug_column.to_sym))
      obj = self.class.find_by slug: the_slug
      count = 2
      while obj && obj != self
        the_slug = append_suffix(the_slug, count)
        obj = self.class.find_by slug: the_slug
        count += 1
      end
      self.slug = the_slug.downcase
    end

    def append_suffix(str, count)
      if str.split('_').last.to_i != 0
        return str.split('_').slice(0...-1).join('_') + '_' + count.to_s
      else
        return str + '_' + count.to_s
      end
    end

    def to_slug(name)
      str = name.strip
      str.gsub!(/\s*[^A-Za-z0-9]\s*/, '_')
      str.gsub!( /_+/, "_")
      str.downcase
    end

    module ClassMethods
      def sluggable_column(col_name)
        self.slug_column = col_name
      end
    end
  end

Is there more than one way to solve this problem?

Of course! The ActiveSupport::Concern was introduced in rails 4. After that, there are plenty ways to extract the duplicate code. One is also popular is use Service Object

So what is service object?

A service object (aka method object) performs one action. It holds the business logic to perform that action

It can not only refactor model but also controller! Besides, you can understand what each service object do(it is a class) better than in concern. And it can write a test to test the service object.

Read more on this article

Resources:

to_param in Ruby on Rails

If I want a custom slug=======================I walk through this cutstom slug.1. create migration `add_slug` to add a column inside the...… Continue reading

What is ORM in Rails mean?

Published on July 14, 2017

Why use thin controller with fat model?

Published on June 29, 2017