Szilard Magyar Szilard Magyar - 4 years ago 96
Ruby Question

calling ruby method in rails controller raises error

I have a rails app and I'm trying to call the methods below from the controller, but I get this error:

undefined local variable or method "service" for #<EventsController:0x007fb6d27da1c8>` for this line: `api_method: service.freebusy.query


What's the problem here? Why can't the
get_busy_events
see the service var if it's defined above it?


controller


include GoogleCalendarApi
.....
@user = current_user
@google = @user.socials.where(provider: "google_oauth2").first
unless @google.blank?
@client = init_google_api_calendar_client(@google)
@result = open_gcal_connection(get_busy_events, @client, @google)



lib/google_api_calendar.rb


def init_google_api_calendar_client(google_account)
#method only called if google_oauth2 social exists
client = Google::APIClient.new
client.authorization.access_token = google_account.token
client.authorization.client_id = ENV['GOOGLE_API_KEY']
client.authorization.client_secret = ENV['GOOGLE_API_SECRET']
client.authorization.refresh_token = google_account.refresh_token
return client
end

def open_gcal_connection(options, initialized_client, social_object)
client = initialized_client
old_token = client.authorization.access_token
service = client.discovered_api('calendar', 'v3')
result = client.execute(options) #after execution you may get new token

# update token if the token that was sent back is expired
new_token = client.authorization.access_token
if old_token != new_token
social_object.update_attribute(token: new_token)
end
return result
end

def get_busy_events
result = open_gcal_connection(
api_method: service.freebusy.query,
body: JSON.dump({ timeMin: '2015-12-24T17:06:02.000Z',
timeMax: '2013-12-31T17:06:02.000Z',
items: social_object.email }),
headers: {'Content-Type' => 'application/json'})
#handling results
end

Answer Source

To answer your question(as I did in the comments):

To fix your method, you have to define the service variable in the action where you are calling it.

As for your posted link: if you look at the get_busy_events method there is a line where service = client.discovered_api('calendar', 'v3')

and it is fine, because it is in the method. The same goes for client that the service declaration depends on- you have to declare them inside the method where you use them.

You should follow the article and make the code as it is there so you would have:

def init_client
  client = Google::APIClient.new
  # Fill client with all needed data
  client.authorization.access_token = @token #token is taken from auth table
  client.authorization.client_id = @oauth2_key
  client.authorization.client_secret = @oauth2_secret
  client.authorization.refresh_token = @refresh_token
  return client
end

which you can use to define client variable in all your other actions and then use the service method:

def get_busy_times
  client = init_client
  service = client.discovered_api('calendar', 'v3')
  @result = client.execute(
    :api_method => service.freebusy.query,
    :body_object => { :timeMin => start_time, #example: DateTime.now - 1.month
                      :timeMax => end_time, #example: DateTime.now + 1.month
                      :items => items
                    },
    :headers => {'Content-Type' => 'application/json'}})
end

EDIT No2:

Since you have a controller, where client is initialized I suggest passing it down as an argument:

include GoogleCalendarApi
.....
@user = current_user
@google = @user.socials.where(provider: "google_oauth2").first
unless @google.blank?
  @client = init_google_api_calendar_client(@google)
  @result = open_gcal_connection(get_busy_events(@client), @client, @google)

and changing your get_busy_events method:

def get_busy_events(client)
  service = client.discovered_api('calendar', 'v3')
  result = open_gcal_connection(
    api_method: service.freebusy.query,
    body: JSON.dump({ timeMin: '2015-12-24T17:06:02.000Z',
                   timeMax: '2013-12-31T17:06:02.000Z',
                   items: social_object.email }),
    headers: {'Content-Type' => 'application/json'})
  #handling results
end

Although this is a bit weird for me(nesting arguments like this) so you should look at refactoring this.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download