Kingsley Simon
Kingsley Simon

Reputation: 2210

call service method from a controller following correct factory patterns

I have the following class

class EvaluateService
  def initialize
  end

  def get_url
  end

  def self.evaluate_service
    @instance ||= new
  end
end

class CheckController < ApplicationController
  def index
    get_url = EvaluateService.get_url
  end
end

The problem here is that i know that i can do evaluate_service = EvaluateService.new and use the object evaluate_service.get_url and it will work fine but i also know that some frown upon the idea of initializing the service object this way and rather there is a way of initializing it via a call, send method in the service class.

Just wondering how do i do this?

Upvotes: 2

Views: 3442

Answers (2)

Drenmi
Drenmi

Reputation: 8777

I think what you're looking for is something like:

class Evaluate
  def initialize(foo)
    @foo = foo
  end

  def self.call(foo)
    new(foo).call
  end

  def call
    url
  end

  private

  def url
    # Implement me
  end
end

Now you can do this in your controller:

class CheckController < ApplicationController
  def index
    @url = Evaluate.call(params)
  end
end

The reason some prefer #call as the entry point is that it's polymorphic with lambdas. That is, anywhere you could use a lambda, you can substitute it for an instance of Evaluate, and vice versa.

Upvotes: 4

Stefan
Stefan

Reputation: 114138

There are various ways to approach this.

If the methods in EvaluateService don't need state, you could just use class methods, e.g.:

class EvaluateService
  def self.get_url
    # ...
  end
end

class CheckController < ApplicationController
  def index
    @url = EvaluateService.get_url
  end
end

In this scenario, EvaluateService should probably be a module.


If you want a single global EvaluateService instance, there's Singleton:

class EvaluateService
  include Singleton

  def get_url
    # ...
  end
end

class CheckController < ApplicationController
  def index
    @url = EvaluateService.instance.get_url
  end
end

But global objects can be tricky.


Or you could use a helper method in your controller that creates a service instance (as needed) and memoizes it:

class EvaluateService  
  def get_url
    # ...
  end
end

class CheckController < ApplicationController
  def index
    @url = evaluate_service.get_url
  end

  private

  def evaluate_service
    @evaluate_service ||= EvaluateService.new
  end
end

Maybe even move it up to your ApplicationController.

Upvotes: 2

Related Questions