Questifer
Questifer

Reputation: 1123

Using one instance of client for external service throughout rails application

This question isn't about a specific external service, but about using the same object throughout an application to prevent re-authentication at every call. I'm building a ruby on rails application that connects to the Salesforce REST API via restforce. As of right now, I create an instance of the restforce object (client) inside of every controller. This slows my application down significantly because it is authenticating into salesforce's api on every page load.

As of right now, I have an initializer file that creates a restforce object that includes the credentials (oauth token, etc.). I would like to use that instance of the client throughout the application to speed things up. At the very least, I would like to authenticate once in each controller so each method has access to one authenticated instance of the object.

restforce.rb (initializer file) require 'restforce'

class RestforceClient
  def restforce
    client = Restforce.new :username => ENV['SALESFORCE_USERNAME'],
      :password       => ENV['SALESFORCE_PASSWORD'],
      :security_token => ENV['SALESFORCE_SECURITY_TOKEN'],
      :client_id      => ENV['SALESFORCE_CLIENT_ID'],
      :client_secret  => ENV['SALESFORCE_CLIENT_SECRET'],
      :host           => ENV['SALESFORCE_HOST'],
      :debugging      => ENV['TRUE']
  end
end

controller example

def foobar
  @user = current_user
  client = Restforce.new
  @fetchdata = client.query("select X from y")
end

def barfoo
  @user = current_user
  client = Restforce.new    
  @fetchdata = client.query("select X from Z")
end

The above controller illustrates the problem I'm encountering. When I load the foobar view, It creates a new instance of restforce. Then when I load the barfoo view, it creates a new instance of restforce. Is there anyway to have one instance of restforce across the controller, or even better, the whole application?

Upvotes: 2

Views: 2017

Answers (2)

ole
ole

Reputation: 5233

I think this is the better way for you:

#config/initializers/client.rb

class RestforceClient
  include Singleton

  def restforce
    @client ||= \
      Restforce.new :username => ENV['SALESFORCE_USERNAME'],
        :password       => ENV['SALESFORCE_PASSWORD'],
        :security_token => ENV['SALESFORCE_SECURITY_TOKEN'],
        :client_id      => ENV['SALESFORCE_CLIENT_ID'],
        :client_secret  => ENV['SALESFORCE_CLIENT_SECRET'],
        :host           => ENV['SALESFORCE_HOST'],
        :debugging      => ENV['TRUE']
  end
end

# app/controllers/application_controller.rb

private

def client
  RestforceClient.instance.restforce
end
helper_method :client

After that you can simply use it:

# controller

def foobar
  @user = current_user
  @fetchdata = client.query("select X from y")
end

# view 

<%= client.query("select X from y") %>

# other services

class MyService
  def some_methods
    result = RestforceClient.instance.restforce
    #...
  end
end

RestforceClient will create Restforce instance only once.

If you want client method in the AR models you can do this:

# config/initializers/extend_ar.rb

module ActiveRecordExtension
  extend ActiveSupport::Concern

  def client
     RestforceClient.instance.restforce
  end
end

# include the extension 
ActiveRecord::Base.send(:include, ActiveRecordExtension)

Upvotes: 6

eloyesp
eloyesp

Reputation: 3285

A good alternative to use Singleton module is to simply use a Constant that you can setup in an Initializer of some sort.

RestforceClient = Restforce.new :username => ENV['SALESFORCE_USERNAME'],
    :password       => ENV['SALESFORCE_PASSWORD'],
    :security_token => ENV['SALESFORCE_SECURITY_TOKEN'],
    :client_id      => ENV['SALESFORCE_CLIENT_ID'],
    :client_secret  => ENV['SALESFORCE_CLIENT_SECRET'],
    :host           => ENV['SALESFORCE_HOST'],
    :debugging      => ENV['TRUE']

The only advantage of a singleton class is the initial time. But this is not an issue with RestForce (and should not be an issue with most clients).

Upvotes: 0

Related Questions