Refactoring Ruby on Rails

Rails / Refactoring: simple factory pattern

Rails / Refactoring: simple factory pattern January 8, 20184 Comments

Let’s start with a sample class:

class SocialMediaPublisher
  def publish(social_media_type, user, message)
    social_media_api = nil
    
    case social_media_type
      when 'facebook'
        social_media_api = Facebook::API.new(user)
      when 'twitter'
        social_media_api = Twitter::API.new(user)
      when 'instagram'
        social_media_api = Instagram::API.new(user)
      else
        fail(InvalidSocialMediaType, social_media_type)
    end
    
    social_media_api.sign_in
    social_media_api.push(message: message)
  end
end

The only different thing here is an object creation and factory pattern is about encapsulating object creation. We will extract now code responsible for object creation to separated class and we will name it SocialMediaPublisherFactory

class SocialMediaPublisherFactory
  def create_social_media_api(social_media_type, user)
    case social_media_type
      when 'facebook'
        Facebook::API.new(user)
      when 'twitter'
        Twitter::API.new(user)
      when 'instagram'
        Instagram::API.new(user)
      else
        fail(InvalidSocialMediaType, social_media_type)
    end
  end
end

We have our simple factory so we can update source class to use it:

class SocialMediaPublisher
  def publish(social_media_type, user, message)
    factory = SocialMediaPublisherFactory
    social_media_api = factory.create_social_media_api(
      social_media_type, user
    )
    
    social_media_api.sign_in
    social_media_api.push(message: message)
  end
end

As you can see there are no implementation details here. You can even add support for another social media provider and you don’t have to update this class as long as you will have the same method names for each new provider.

Having problems with refactoring your Ruby on Rails app?

Hit me on twitter or use contact form and let me know how can I help you!

Download free RSpec & TDD ebook

Do you want to earn more or jump to the next level in your company? Do you know that testing skills are one of the most desired skills? There is only first step: start testing and do it right. My ebook can help you. Subscribe to the newsletter to get a free copy of the book.

4 comments

  1. You seems have lost `user` in Factory class. Where it received from?
    And if you give user as argument for `create_social_media_api` – it’s actually increasing coupling of this methods, and it’s bad.
    Ways of evading:
    1. Just use `social_media_api = case ….`. Ruby allows it well.
    2. Return only class name from Factory, then make an instance with your user and do other stuff.
    Second one is not working if you have different required argument set for construction of API class. That’s one of the reasons why I really don’t like factories. Good hierarchical inheritance for API classes works better, and don’t create in-code level of abstraction (delegating it to type system) which is actually not existed in real life.

    1. You are right, I forget about the user object – I updated code, thanks! In case of other points, I agree with you but I wanted to show a more general overview of this pattern so I didn’t implement code where a class name is returned.

Leave a Reply

Your email address will not be published. Required fields are marked *