Patreon / patreon-ruby

Interact with the Patreon API via OAuth
Apache License 2.0
36 stars 13 forks source link

undefined method `pledges=' for nil:NilClass #7

Open glacials opened 6 years ago

glacials commented 6 years ago

After upgrading the Patreon gem to v0.3.0, performing the OAuth flow using the following code snippet throws an exception on the last line during the callback to my service. Downgrading the Patreon gem to v0.2.0 solves the error.

Initial sendover:

redirect_to("https://www.patreon.com/oauth2/authorize?response_type=code&client_id=#{ENV['PATREON_CLIENT_ID']}&redirect_uri=#{redirect_uri}")

Callback:

oauth_client = Patreon::OAuth.new(ENV['PATREON_CLIENT_ID'], ENV['PATREON_CLIENT_SECRET'])

tokens = oauth_client.get_tokens(params[:code], redirect_uri)
access_token = tokens['access_token']
refresh_token = tokens['refresh_token']

api_client = Patreon::API.new(access_token)
user_response = api_client.fetch_user() # raises exception
undefined method `pledges=' for nil:NilClass

app/controllers/patreon_users_controller.rb:16:in `in' # the user_response line

I don't see any patch notes so I'm unsure if this is an intentional change in how the gem should be used, or a bug.

I'm running Rails 5.1.4 on Ruby 2.4.2. Full trace is below. Thanks for any assistance!

json-api-vanilla (1.0.1) lib/json-api-vanilla/parser.rb:152:in `set_key'
json-api-vanilla (1.0.1) lib/json-api-vanilla/parser.rb:94:in `block (2 levels) in build'
json-api-vanilla (1.0.1) lib/json-api-vanilla/parser.rb:80:in `each'
json-api-vanilla (1.0.1) lib/json-api-vanilla/parser.rb:80:in `block in build'
json-api-vanilla (1.0.1) lib/json-api-vanilla/parser.rb:76:in `each'
json-api-vanilla (1.0.1) lib/json-api-vanilla/parser.rb:76:in `build'
json-api-vanilla (1.0.1) lib/json-api-vanilla/parser.rb:20:in `parse'
/usr/local/bundle/bundler/gems/patreon-ruby-0530a2fbb30f/lib/patreon/api.rb:39:in `get_json'
/usr/local/bundle/bundler/gems/patreon-ruby-0530a2fbb30f/lib/patreon/api.rb:13:in `fetch_user'
app/controllers/patreon_users_controller.rb:16:in `in'
actionpack (5.1.4) lib/action_controller/metal/basic_implicit_render.rb:4:in `send_action'
actionpack (5.1.4) lib/abstract_controller/base.rb:186:in `process_action'
actionpack (5.1.4) lib/action_controller/metal/rendering.rb:30:in `process_action'
actionpack (5.1.4) lib/abstract_controller/callbacks.rb:20:in `block in process_action'
activesupport (5.1.4) lib/active_support/callbacks.rb:131:in `run_callbacks'
actionpack (5.1.4) lib/abstract_controller/callbacks.rb:19:in `process_action'
actionpack (5.1.4) lib/action_controller/metal/rescue.rb:20:in `process_action'
actionpack (5.1.4) lib/action_controller/metal/instrumentation.rb:32:in `block in process_action'
activesupport (5.1.4) lib/active_support/notifications.rb:166:in `block in instrument'
activesupport (5.1.4) lib/active_support/notifications/instrumenter.rb:21:in `instrument'
activesupport (5.1.4) lib/active_support/notifications.rb:166:in `instrument'
actionpack (5.1.4) lib/action_controller/metal/instrumentation.rb:30:in `process_action'
actionpack (5.1.4) lib/action_controller/metal/params_wrapper.rb:252:in `process_action'
activerecord (5.1.4) lib/active_record/railties/controller_runtime.rb:22:in `process_action'
actionpack (5.1.4) lib/abstract_controller/base.rb:124:in `process'
actionview (5.1.4) lib/action_view/rendering.rb:30:in `process'
actionpack (5.1.4) lib/action_controller/metal.rb:189:in `dispatch'
actionpack (5.1.4) lib/action_controller/metal.rb:253:in `dispatch'
actionpack (5.1.4) lib/action_dispatch/routing/route_set.rb:49:in `dispatch'
actionpack (5.1.4) lib/action_dispatch/routing/route_set.rb:31:in `serve'
actionpack (5.1.4) lib/action_dispatch/journey/router.rb:50:in `block in serve'
actionpack (5.1.4) lib/action_dispatch/journey/router.rb:33:in `each'
actionpack (5.1.4) lib/action_dispatch/journey/router.rb:33:in `serve'
actionpack (5.1.4) lib/action_dispatch/routing/route_set.rb:834:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
omniauth (1.7.1) lib/omniauth/strategy.rb:190:in `call!'
omniauth (1.7.1) lib/omniauth/strategy.rb:168:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
omniauth (1.7.1) lib/omniauth/builder.rb:63:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/rack/agent_hooks.rb:30:in `traced_call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/rack/browser_monitoring.rb:32:in `traced_call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
meta_request (0.4.3) lib/meta_request/middlewares/app_request_handler.rb:13:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
meta_request (0.4.3) lib/meta_request/middlewares/meta_request_handler.rb:13:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
rack (2.0.3) lib/rack/etag.rb:25:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
rack (2.0.3) lib/rack/conditional_get.rb:25:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
rack (2.0.3) lib/rack/head.rb:12:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
rack (2.0.3) lib/rack/session/abstract/id.rb:232:in `context'
rack (2.0.3) lib/rack/session/abstract/id.rb:226:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
actionpack (5.1.4) lib/action_dispatch/middleware/cookies.rb:613:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
activerecord (5.1.4) lib/active_record/migration.rb:556:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
actionpack (5.1.4) lib/action_dispatch/middleware/callbacks.rb:26:in `block in call'
activesupport (5.1.4) lib/active_support/callbacks.rb:97:in `run_callbacks'
actionpack (5.1.4) lib/action_dispatch/middleware/callbacks.rb:24:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
actionpack (5.1.4) lib/action_dispatch/middleware/executor.rb:12:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
better_errors (2.4.0) lib/better_errors/middleware.rb:59:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
actionpack (5.1.4) lib/action_dispatch/middleware/debug_exceptions.rb:59:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
rack-contrib (1.2.0) lib/rack/contrib/response_headers.rb:17:in `call'
meta_request (0.4.3) lib/meta_request/middlewares/headers.rb:16:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
actionpack (5.1.4) lib/action_dispatch/middleware/show_exceptions.rb:31:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
railties (5.1.4) lib/rails/rack/logger.rb:36:in `call_app'
railties (5.1.4) lib/rails/rack/logger.rb:24:in `block in call'
activesupport (5.1.4) lib/active_support/tagged_logging.rb:69:in `block in tagged'
activesupport (5.1.4) lib/active_support/tagged_logging.rb:26:in `tagged'
activesupport (5.1.4) lib/active_support/tagged_logging.rb:69:in `tagged'
railties (5.1.4) lib/rails/rack/logger.rb:24:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
sprockets-rails (3.2.1) lib/sprockets/rails/quiet_assets.rb:13:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
actionpack (5.1.4) lib/action_dispatch/middleware/remote_ip.rb:79:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
request_store (1.3.2) lib/request_store/middleware.rb:9:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
actionpack (5.1.4) lib/action_dispatch/middleware/request_id.rb:25:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
rack (2.0.3) lib/rack/method_override.rb:22:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
rack (2.0.3) lib/rack/runtime.rb:22:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
activesupport (5.1.4) lib/active_support/cache/strategy/local_cache_middleware.rb:27:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
actionpack (5.1.4) lib/action_dispatch/middleware/executor.rb:12:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
actionpack (5.1.4) lib/action_dispatch/middleware/static.rb:125:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
rack (2.0.3) lib/rack/sendfile.rb:111:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
railties (5.1.4) lib/rails/engine.rb:522:in `call'
newrelic_rpm (4.5.0.337) lib/new_relic/agent/instrumentation/middleware_tracing.rb:92:in `call'
puma (3.10.0) lib/puma/configuration.rb:225:in `call'
puma (3.10.0) lib/puma/server.rb:605:in `handle_request'
puma (3.10.0) lib/puma/server.rb:437:in `process_client'
puma (3.10.0) lib/puma/server.rb:301:in `block in run'
puma (3.10.0) lib/puma/thread_pool.rb:120:in `block in spawn_thread'
joshbuddy commented 6 years ago

Hey, I just tried out the example and hit an error. I updated the url to use /api instead, and now it's working (for me at least). The pull request is over here https://github.com/Patreon/patreon-ruby/pull/8. Can you try this out and let me know if it fixes it for you?

joshbuddy commented 6 years ago

Hey, actually, I don't think that will help you. Instead, if possible can you run with DEBUG=1 set in your env (and use master of this gem). It will capture some debug output, and then, if you don't mind using some secure method, or cutting out the tokens, I think that will help us track down the issue.

milesegan commented 6 years ago

Seeing this issue as well. Using master branch from github didn't help.

YSavir commented 6 years ago

Getting this error as well.

@joshbuddy I re-ran it with DEBUG=1. I'm not very familiar with these responses and am not sure which parts are sensitive data. Do you have any secure methods you recommend for sharing the output?

wakproductions commented 6 years ago

Encountering the same problem here. Appears to be an issue with JSON::Api::Vanilla.parse. Why not just use native Ruby JSON.parse?

From: /patreon-ruby/lib/patreon/api.rb @ line 34 Patreon::API#get_parse_json:

31: def get_parse_json(suffix)
32:   json = get_json(suffix)
33:   binding.pry

=> 34: parse_json(json) 35: end

[1] pry(#<Patreon::API>)> json
=> "{\n    \"data\": {\n        \"attributes\": {\n            \"about\": null,\n            \"created\": \"2017-03-27T22:39:59+00:00\",\n            \"discord_id\": null,\n            \"email\": \"wak@wakproductions.com\",\n            \"facebook\": null,\n            \"facebook_id\": null,\n            \"first_name\": \"Greenspud\",\n            \"full_name\": \"Greenspud Trades\",\n            \"gender\": 0,\n            \"has_password\": true,\n            \"image_url\": \"https://c10.patreonusercontent.com/3/eyJ2IjoiMSIsInciOjIwMH0%3D/patreon-media/user/5462977/a152f52e08ec4099b3212547e377a954?token-time=2145916800&token-hash=96pPoipGZzm6gTSV1dzdQsuIr47TbCzn1wzvW_7UAog%3D\",\n            \"is_deleted\": false,\n            \"is_email_verified\": true,\n            \"is_nuked\": false,\n            \"is_suspended\": false,\n            \"last_name\": \"Trades\",\n            \"social_connections\": {\n                \"deviantart\": null,\n                \"discord\": null,\n                \"facebook\": null,\n                \"spotify\": null,\n                \"twitch\": null,\n                \"twitter\": null,\n                \"youtube\": null\n            },\n            \"thumb_url\": \"https://c10.patreonusercontent.com/3/eyJoIjoxMDAsInYiOiIxIiwidyI6MTAwfQ%3D%3D/patreon-media/user/5462977/a152f52e08ec4099b3212547e377a954?token-time=2145916800&token-hash=FioodKfrYEtzdXUmk5EXJ8KpY3PIKtJFeG6HaIbjZJA%3D\",\n            \"twitch\": null,\n            \"twitter\": null,\n            \"url\": \"https://www.patreon.com/greenspudtrades\",\n            \"vanity\": \"greenspudtrades\",\n            \"youtube\": null\n        },\n        \"id\": \"5462977\",\n        \"relationships\": {\n            \"pledges\": {\n                \"data\": []\n            }\n        },\n        \"type\": \"user\"\n    },\n    \"links\": {\n        \"self\": \"https://www.patreon.com/api/user/5462977\"\n    }\n}"

[3] pry(#<Patreon::API>)> JSON::Api::Vanilla.parse(json)
NoMethodError: undefined method `pledges=' for nil:NilClass
hovancik commented 5 years ago

Can confirm that this is issue with JSON::Api::Vanilla.parse. I have the same issue in another place #23

JSON::Api::Vanilla has issue opened https://github.com/trainline/json-api-vanilla/issues/4 from some time ago.

Patreon should drop this dependency.

hovancik commented 5 years ago

Temporary workaround:

In Gemfile use my fork:

# Patreon
gem 'patreon', git: 'https://github.com/hovancik/patreon-ruby', branch: 'feature/remove-json-api-vanilla'

Then update your code to not use broken json-api-vanilla, ie to get all your patron IDs:

      api_client = Patreon::API.new(ENV.fetch('PATREON_ACCESS_TOKEN'))
      campaign_response = api_client.fetch_campaign
      campaign_id = campaign_response['data'][0]['id']
      all_pledges = []
      cursor = nil
      loop do
        page_response = api_client.fetch_page_of_pledges(campaign_id, count: 25, cursor: cursor)
        all_pledges += page_response['data']
        next_page_link = page_response['links']['next']
        break unless next_page_link
        parsed_query = CGI::parse(next_page_link)
        cursor = parsed_query['page[cursor]'][0]
      end
      all_pledges.map { |pledge| pledge['relationships']['patron']['data']['id'] }
RicardoRojo commented 5 years ago

Thanks @hovancik . I was getting crazy with the Vanilla parse. This workaround works great.