Search code examples
ruby-on-railsshopifybackground-process

Shopify API calls not working in Rails background job


In my Rails controller action, I have a method that does a bunch of Shopify API calls. Things like: ShopifyAPI::Product.all()

ShopifyAPI::Product.find(:all, params: {title: title})

ShopifyAPI::Product.create(title: title, body_html: description, images: images, tags: tags, product_type: product_type)

All of it does what I want...very neat.

The problem is that I'm going to be uploading a CSV and using this controller method. It's fine if I have like 8 line items, but very quickly it gets slow. So, I thought, let's move it to a background worker.

I'm using Redis/Resque to get everything going and using some dummy outputs (i.e. puts 'Hi there champ!') I've confirmed that the background worker is configured properly and executing when and where it should be. Neat.

So then I put bits and pieces of my controller action in and output that. That all works until I hit my Shopify API calls. I can call .new on about any object, but the when I try to .find, .all, or .create any valid object (which worked before I abstracted it to the background job), it sort of goes dead. Super descriptive! I've tried to output what's going on via logger and puts but I can't seem to generate much output of what's going on, but I have isolated it down to the Shopify API work. I thought that, even though I have an initializer that specifies my passwords, site, API keys, secrets, etc, I might need to reinitialize my Shopify session, as per their setup docs here. I either did it wrong, or that did solve the issue.

At this point I'm sure I'm just missing something in the docs, but I cannot find out how to make these necessary API calls from my background job. Any thoughts on what I might be doing obviously wrong that could solve this? Anyone dealt with anything similar?


Solution

  • Turns out this has to do with where the Shopify Engine was mounted. In my routes.rb I have the following (in addition to other routes; these are the two pertinent ones):

    mount ShopifyApp::Engine, at: '/'
    root to: 'products#index'
    

    This is all fine and good, but sort of forces the context of your Shopify API calls to be made within the context of the products.rb index controller action...without some changes. 2 ways to do this, one obviously the more Railsy way to do it:

    Option 1:

    Include

    session = ShopifyApp::SessionRepository.retrieve(1)
    ShopifyAPI::Base.activate_session(session)
    

    at the beginning of any file in which you want to make Shopify API calls. This sets the session (assuming you only have 1 store, by the way...this is using the retrieve method to retrieve store 1. Risky assumption), authenticate to the API, and everything in life is good.

    Option 2:

    Class inheritance for the win. Have all your controllers that are making API calls inherit from ShopifyApp::AuthenticatedController. This makes the initializer actually work, and that's it. This is (in retrospect) the clear and obvious way to go. Have an order controller? class OrdersController < ShopifyApp::AuthenticatedController and done: order = ShopifyAPI::Order.find(params[:id]) does exactly what you'd expect it to.