I have a rails app with google calendar API integrated. App is deployed on heroku. The following code is working in localhost but I getting nomethoderror in production as shown below. Why is this happening?
errors for get_own_events:
Attempting refresh of access token & retry of request
2016-02-10T13:24:34.161850+00:00 app[web.1]:
2016-02-10T13:24:34.161853+00:00 app[web.1]: NoMethodError (undefined method `each' for nil:NilClass):
2016-02-10T13:24:34.161854+00:00 app[web.1]: lib/google_calendar_api.rb:91:in `get_own_events'
2016-02-10T13:24:34.161855+00:00 app[web.1]: app/controllers/events_controller.rb:18:in `index'
errors for get busy events:
2016-02-10T13:24:00.716112+00:00 app[web.1]: Attempting refresh of access token & retry of request
2016-02-10T13:24:00.779120+00:00 app[web.1]: NoMethodError (undefined method `[]' for nil:NilClass):
2016-02-10T13:24:00.779121+00:00 app[web.1]: lib/google_calendar_api.rb:38:in `get_busy_events'
2016-02-10T13:24:00.779121+00:00 app[web.1]: app/controllers/events_controller.rb:20:in `index'
events_controller
if params['start'] && params['end']
@start_time = params['start'].to_datetime.rfc3339
@end_time = params['end'].to_datetime.rfc3339
@timezone = params['timezoneParam']
if @user == @current_user
@results = get_own_events(@google, @start_time, @end_time, @timezone)
else
@results = get_busy_events(@google, @start_time, @end_time, @timezone)
end
end
get_own_events method:
def get_own_events(social_object, start_time, end_time, timezone)
client = init_google_api_calendar_client(social_object)
old_token = client.authorization.access_token
service = client.discovered_api('calendar', 'v3')
#API request/response
result_raw = client.execute(
:api_method => service.events.list,
:parameters => { 'calendarId' => social_object.email,
'timeMin' => start_time,
'timeMax' => end_time,
'timeZone' => timezone },
:headers => {'Content-Type' => 'application/json'})
#token refresh if needed
new_token = client.authorization.access_token
if old_token != new_token
social_object.update_attribute(:token, new_token)
get_own_events(social_object, start_time, end_time, timezone)
end
#API response parsing
result = JSON.parse(result_raw.body)['items']
#result_timezone = JSON.parse(result_raw.body)['timeZone']
#changing response to fullcalendar format
formatted_event_array = []
result.each do |event| #THIS IS LINE 91
start_time = event['start']['dateTime'].to_datetime.rfc822
end_time = event['end']['dateTime'].to_datetime.rfc822
#timezone = result_timezone
all_day = false
title = event['summary']
formatted_event = {}
formatted_event['title'] = title
formatted_event['start'] = start_time
formatted_event['end'] = end_time
formatted_event['allDay'] = all_day
formatted_event_array << formatted_event
end
return formatted_event_array
end
get_busy_events method:
def get_busy_events(social_object, start_time, end_time, timezone)
client = init_google_api_calendar_client(social_object)
old_token = client.authorization.access_token
service = client.discovered_api('calendar', 'v3')
#API request/response
result_raw = client.execute(
:api_method => service.freebusy.query,
:body => JSON.dump({
:timeMin => start_time,
:timeMax => end_time,
:timeZone => timezone,
:items => [{ :id => social_object.email }]}),
:headers => {'Content-Type' => 'application/json'})
#token refresh if needed
new_token = client.authorization.access_token
if old_token != new_token
social_object.update_attribute(:token, new_token)
get_busy_events(social_object,start_time, end_time, timezone)
end
#API response parsing
result = JSON.parse(result_raw.body)['calendars'][social_object.email]['busy'] #THIS IS LINE 38
#changing response to fullcalendar format
formatted_event_array = []
result.each do |event|
start_time = event['start'].to_datetime.rfc822
end_time = event['end'].to_datetime.rfc822
formatted_event = {}
formatted_event['title'] = 'busy'
formatted_event['start'] = start_time
formatted_event['end'] = end_time
#no allDay in freebusy response, so time difference must be checked
if event['start'].to_datetime + 1.day <= event['end'].to_datetime
formatted_event['allDay'] = true
else
formatted_event['allDay'] = false
end
formatted_event_array << formatted_event
end
return formatted_event_array
end
Effectively it's this
result = JSON.parse(result_raw.body)['calendars'][social_object.email]['busy']
If JSON.parse(result_raw.body)['calendars'][social_object.email]['busy']
is nil then this
result.each do |event|
# code
end
Is attempting to iterate over nil.
You could fix that with a guard clause
return formatted_event_array if result.nil?
result.each do |event|
# code
end
But to me that's papering over the cracks somewhat. The other error is because of that same line.
Assuming
parsed_body = JSON.parse(result_raw.body)
By chaining the hash calls without checking it'll throw your error if
parsed_body['calendars']
is nil or if
parsed_body['calendars'][social_object.email]
is nil
So effectively you want to check if those both exist, and that parsed_body['calendars'][social_object.email]['busy']
exists. If they don't then presumably return the empty array
So
if parsed_body['calendars'] && parsed_body['calendars'][social_object.email] && parsed_body['calendars'][social_object.email]['busy']