3

I am trying to set up the Zendesk API in my app, I have decided to go with the API that was built by Zendesk

I have set up the initializer object to load the client.

config/initializers/zendesk.rb

require 'zendesk_api'

client = ZendeskAPI::Client.new do |config|
  # Mandatory:
  config.url = Rails.application.secrets[:zendesk][:url]

  # Basic / Token Authentication
  config.username = Rails.application.secrets[:zendesk][:username]
  config.token = Rails.application.secrets[:zendesk][:token]

  # Optional:

  # Retry uses middleware to notify the user
  # when hitting the rate limit, sleep automatically,
  # then retry the request.
  config.retry = true

  # Logger prints to STDERR by default, to e.g. print to stdout:
  require 'logger'
  config.logger = Logger.new(STDOUT)

  # Changes Faraday adapter
  # config.adapter = :patron

  # Merged with the default client options hash
  # config.client_options = { :ssl => false }

  # When getting the error 'hostname does not match the server certificate'
  # use the API at https://yoursubdomain.zendesk.com/api/v2
end

This is pretty much copy paste from the site, but I have decided on using the token + username combination.

I then created a service object that I pass a JSON object and have it construct tickets. This service object is called from a controller.

app/services/zendesk_notifier.rb

class ZendeskNotifier
  attr_reader :data

  def initialize(data)
    @data = data
  end

  def create_ticket
    options = {:comment => { :value => data[:reasons] }, :priority => "urgent" }
    if for_operations?
      options[:subject] = "Ops to get additional info for CC"
      options[:requester] = { :email => 'originations@testing1.com' }
    elsif school_in_usa_or_canada?
      options[:subject] = "SRM to communicate with student"
      options[:requester] = { :email => 'srm@testing2.com' }
    else
      options[:subject] = "SRM to communicate with student"
      options[:requester] = { :email => 'srm_row@testing3.com' }
    end
    ZendeskAPI::Ticket.create!(client, options)
  end

  private
  def for_operations?
    data[:delegate] == 1
  end

  def school_in_usa_or_canada?
    data[:campus_country] == "US" || "CA"
  end
end

But now I am getting

NameError - undefined local variable or method `client' for #<ZendeskNotifier:0x007fdc7e5882b8>:
  app/services/zendesk_notifier.rb:20:in `create_ticket'
  app/controllers/review_queue_applications_controller.rb:46:in `post_review'

I thought that the client was the same one defined in my config initializer. Somehow I think this is a different object now. I have tried looking at their documentation for more information but I am lost as to what this is?

legendary_rob
  • 12,792
  • 11
  • 56
  • 102

2 Answers2

4

If you want to use the client that is defined in the initializer you would need to make it global by changing it to $client. Currently you have it setup as a local variable.

danielrsmith
  • 4,050
  • 3
  • 26
  • 32
  • Yeah, so my thinking is if it was then the same variable they would have made it a global variable in the documentation right? Or are they configuring the client in the same file that they then use `ZendeskAPI::Ticket.create!` action call. I am also a bit weary of creating a global variable from the config, is that good practice? – legendary_rob Jun 09 '16 at 15:51
  • 1
    I think their documentation is assuming you put the client configuration in the same scope as where you are executing it. Is it good practice to do a global variable, I don't see it as horrible practice for this kind of thing. I have seen it done pretty commonly with the usage of Redis in a Rails initializer. You other option is to create a service that you can call to get the client. `client = ZendeskService.client` – danielrsmith Jun 09 '16 at 16:02
4

I used a slightly different way of initializing the client, copying from this example rails app using the standard Zendesk API gem: https://github.com/devarispbrown/zendesk_help_rails/blob/master/app/controllers/application_controller.rb

As danielrsmith noted, the client variable is out of scope. You could instead have an initializer like this:

config/initializers/zendesk_client.rb:

class ZendeskClient < ZendeskAPI::Client
  def self.instance
    @instance ||= new do |config|
      config.url = Rails.application.secrets[:zendesk][:url]
      config.username = Rails.application.secrets[:zendesk][:username]
      config.token = Rails.application.secrets[:zendesk][:token]
      config.retry = true
      config.logger = Logger.new(STDOUT)
    end
  end
end

Then return the client elsewhere by client = ZendeskClient.instance (abridged for brevity):

app/services/zendesk_notifier.rb:

class ZendeskNotifier
  attr_reader :data

  def initialize(data)
    @data = data
    @client = ZendeskClient.instance
  end

  def create_ticket
    options = {:comment => { :value => data[:reasons] }, :priority => "urgent" }
    ...
    ZendeskAPI::Ticket.create!(@client, options)
  end
  ...
end

Hope this helps.

jpalmieri
  • 1,539
  • 1
  • 15
  • 25