Note: This project is currently under development!
Reduce those unnecessary API calls!!
ShopifyProductSink is a Rails engine to simplify working with Shopify by keeping a shops products synchronized with a local copy.
- Provides functionality to import products from Shopify
- Provides an import helper which can do all the heavy lifting of pulling in products
- Provides a simple way to register webhooks for product changes
- Provides a module that can be included to take care of all the "boring" parts of webhook verification
- Provide a default webhooks controller that will do basic product synchronization
- Do proper shop scoping since right now there isn't any and there could possibly be some data leakage
- Refactor API createable integration objects such that them and their migrations aren't imported when the engine is installed
- Remove all CSS and JavaScript since it's not actually needed for this engine to work whatsoever
Right now I have no idea what I'm doing when it comes to engines, so I'm just speccing the docs based on the hooking into an application section on the Rails Guides
Until I get a rubygem setup you'll need to link right to the github repository in your Gemfile:
gem 'shop_product_sink', git: 'https://github.com/csaunders/shopProductSink'
Mount the application in your routes file:
mount ShopProductSink::Engine, at: "product_sink"
rake shop_product_sink:install:migrations
rake db:migrate SCOPE=shop_product_sink
Add shop scoping to your products in a couple of steps. You'll need a Shop
model, which can be looked up by the shop's myshopify.com domain.
1. Add a has_many :products
association to your shop model
# app/models/shop.rb
class Shop < ActiveRecord::Base
has_many :products, class_name: 'ShopProductSink::Product'
end
Note: the class_name
must be set to the engine's Product model.
2. Set the shop class name in an initializer
# config/initializers/shop_product_sink.rb
# Set the model that ShopProductSink::Product will belong to
ShopProductSink.shop_class = 'Shop'
This will set the belongs_to relation for ShopProductSink::Product
. Set it as a string.
3. Let the ShopProductSink
know how to find
a single shop based on its shopify domain
By default, ShopProductSink
will look up the shop using your Shop
model's find_by_domain
method. So, if your Shop model has a domain
attribute that corresponds to the Shop's myshopify domain (e.g., bagelshop.myshopify.com), then you're set.
Otherwise, you'll need to add your own method to look up a shop by its myshopify.com domain:
# app/models/shop.rb
def self.find_by_shop_domain(shop_domain)
self.where(myshopify_domain: shop_domain).first
end
# config/initializers/shop_product_sink.rb
# Set the method within shop_class above to lookup a shop by its myshopify.com domain
ShopProductSink.shop_lookup_method = :find_by_shop_domain
If your app is already using ShopProductSink
, upgrading is similar to setup.
- Update the gem using bundler:
bundle update shop_product_sink
-
Go through the Install and Run migrations step above to update your database tables.
-
Go through the steps for Shop Scoping above if your app will be used by multiple shops.
The engine comes with two utility functions that make it easier to integrate product synchronization into your app.
# Partner App Initialization
importer = ShopProductSink::Importers::Product.new(
shop: 'yourshop.myshopify.com',
token: 'abracadabra'
)
importer.import
# Alternative -- Private App Initialization
importer = ShopProductSink::Importers::Product.new(
site: 'https://apikey:password@yourshop.myshopify.com/admin'
)
importer.import
Secondly it comes with a utility to make registering webhooks easier. There are a few catches if you want to have it be more automated. There are routes setup for an included Webhooks Controller that you can leverage if you don't want to handle validating webhooks on your own.
1. Setup your applications default host
# application.rb
Rails.application.routes.default_url_options[:host] = "your.domain.tld"
2. Include your Application Secret in your ENV
You should probably be doing this already anyway since it's good practice. The only problem is you are somewhat forced onto a naming convention for at least one of your API variables.
The variable that needs to be set in your environment is SHOPIFY_APP_SECRET
3. Register to receive Product change webhooks whenever it is necessary
ShopProductSink::WebhookRegistration.register(
shop: 'yourshop.myshopify.com',
token: 'abracadabra'
)
That's all you need. As product webhooks come in, ShopProductSink will keep local product data in sync with Shopify's for the shop in question.
You don't have to!!! If you want you can create your own webhooks handler.
You are required to do a few things if you use your own webhooks controller/handler:
- Include the
ShopProductSink::Webhooks
module in it. - Implement
application_secret