0

I want to move some rails business logic into a service, following correct OOP protocol. I'm following the method recommended here: Private module methods in Ruby

Ultimately, I want to move business logic out of models and controllers into services, which are Plain Old Ruby Objects. So, models will just be concerned with persistence, scoping, & validation.

Is this the correct way to make a service module?

Version 2:

module CategorizeJobs

  def self.fetch( location, category_name )
    c = Categorizer.new( location, category_name )
    c.get_jobs
  end

  class Categorizer

    def initialize(location, category_name)
      @location = location
      @category_name = category_name
    end

    def get_jobs
      job_ids = get_correct_jobs
      Category.includes(:jobs).where( jobs: { id:  job_ids } )
    end

    private

      def get_correct_jobs
        jobs = filter_by_location
        jobs = filter_by_category(jobs)

        jobs.collect(&:id)
      end

      def filter_by_category(jobs)
        return jobs unless @category_name.present?

        category = Category.where(name: @category_name).first
        if category
          jobs = jobs.where(category: category)
        end

        jobs
      end

      def filter_by_location
        if @location.present?
          jobs = get_jobs_at_location
        else
          jobs = Job.open
        end
      end

      def get_jobs_at_location(location)
        Job.joins(:location).within(20, origin: @location).open
      end

  end

end

Version 1:

 module CategorizeJobs

  def self.fetch( location, category_name )
    c = Categorizer.new
    c.perform( location, category_name )
  end


  class Categorizer

    def perform( location, category_name )
      job_ids = get_correct_jobs(location, category_name)
      Category.includes(:jobs).where( jobs: { id:  job_ids } )
    end

    private

      def get_correct_jobs(location, category_name)
        jobs = filter_by_location(location)
        jobs = filter_by_category(jobs, category_name)

        jobs.collect(&:id)
      end

      def filter_by_category(jobs, category_name)
        return jobs unless category_name

        category = Category.where(name: category_name).first
        if category
          jobs = jobs.where(category: category)
        end

        jobs
      end

      def filter_by_location(location)
        if location
          jobs = get_jobs_at_location(location)
        else
          jobs = Job.open
        end
      end

      def get_jobs_at_location(location)
        Job.joins(:location).within(20, origin: location).open
      end

  end

end
Community
  • 1
  • 1
Will Taylor
  • 1,994
  • 2
  • 23
  • 36

1 Answers1

3

There is a gem by the name of Aldous that helps you implement service objects based architecture into your Rails applications. Have a look at it.

If you need further help on how to use it and architect your application, you can look at this and this for more help.

Noman Ur Rehman
  • 6,707
  • 3
  • 24
  • 39
  • Thanks! Had a read through - good idea. I don't think I want to completely re-architect my app, I have no idea how this will work with other gems I'm using - and I'll have to train any developers I bring onto the project in Aldous – Will Taylor May 14 '15 at 11:33
  • @WillTaylor No need to re-architect your app or take the learning curve to implement the gem. Just understand how service objects are implemented through those resources and hack away your project. – Noman Ur Rehman May 14 '15 at 13:10