Rails5, Webpack, React, PolarisでShopifyアプリの構築方法

## はじめに

この記事では、`Ruby on Rails`を用いてShopifyアプリ開発のセットアップ方法を紹介します。
また、Shopify公式のUIコンポーネント`Polaris`についても導入までを行いたいと思います。


## Shopifyとは

簡単に言うと高機能なECプラットフォームです。
豊富なAPIがあるため、既存機能で実現出来ないようなものも、Shopifyアプリというもので拡張を行えば様々なことが実現出来たりします。
ShopifyアプリはWordpressでいうプラグインのようなものと思っていただければわかりやすいかと思います。

またShopifyは開発者にとっても嬉しいことにアプリの収益の80%を受け取れるようになっています。
詳しくは[公式](https://help.shopify.com/ja/partners/making-apps)をご覧ください。

## 環境

* Ruby 2.5.3
* Rails 5.2.2
* Mac OSX 10.14.4

## 1. アプリケーションの作成

reactを使い、databaseにmysqlを使用し、アプリケーションを作成します。

```
$ rails new shopifyapp --webpack=react -d mysql -T

$ cd shopifyapp
```

## 2. shopify_app gemのインストール

アプリケーションの作成が終わったら、アプリ化するためのgemをインストールします。
`Gemfile`に以下を追記します。

```yaml
gem 'shopify_app'
```

上記追記し、保存したら、

```
$ bundle install

$ rails db:create
```

までを実行。

## 3. `ngrok`で公開urlを作成

Shopifyでは、アプリとして登録するためにオンライン上に公開されているurlが必要となります。
それを簡単に実現してくれる`ngrok`を使っていきます。

`ngrok`をインストールしていない場合、以下よりインストールします。

```
$ brew cask install ngrok
```

有料版ではサブドメインの指定が出来るようになっていますので、サブドメインで進めていきます。
無料版では乱数のドメインとなります。

```
$ ngrok http -subdomain=shopifyapp 5000
```

ここで表示される、`https~`から始まるurlをコピーします。
上記で作成すると、`https://shopifyapp.ngrok.io`のようになります。

## 4. Shopifyパートナーアカウントからアプリを登録

アプリを作成するには、パートナーアカウントが必要となるので、まだ持っていない場合は、以下より作成します。
[https://www.shopify.jp/partners](https://www.shopify.jp/partners)

パートナーアカウントを作成したら、管理画面のサイドバーより、Apps > Create appからアプリを登録します。
その際にアプリ名、アプリURL、リダイレクトURLの情報を入力するよう求められるので、先ほどのngrokで作成したurl情報を入力します。

項目 | 値
---- | ---
App name | ここはなんでもいい
App URL | https://shopifyapp.ngrok.io
Whitelisted redirection URL(s) | https://shopifyapp.ngrok.io/auth/shopify/callback

とします。
最後の`Whitelisted`は`ドメイン/auth/shopify/callback`とすればokです

上記入力後、APIキーとシークレットキーが発行されるかと思うのですが、それらをメモしておきます。

## 5. RailsアプリケーションをShopifyアプリ化

2で`shopify_app`gemがインストールされている状態かと思いますが、以下で初期設定を行なっていきます。

```
// 設定ファイルなどを生成
$ rails g shopify_app:install --api_key APIキー --secret シークレットキー

// shopモデルとmigrationファイルの作成
$ rails g shopify_app:shop_model

// アプリのトップページ用のcontrollerとviewを作成
$ rails g shopify_app:home_controller

// migrate
$ rails db:migrate
```

## 6. ルーティングを設定

`shopify_app`gemがルーティングをmountしてくれてるかと思うのですが、以下のように修正します。

`config/routes.rb`

```rb
Rails.application.routes.draw do
  root :to => 'home#index'
  mount ShopifyApp::Engine, at: '/'
end
```

## 7. home_controllerを修正

`rails g shopify_app:home_controller`で作成された`home_controller`は以下のようになっています。

`app/controllers/home_controller.rb`

```rb
# frozen_string_literal: true

class HomeController < AuthenticatedController
  def index
    @products = ShopifyAPI::Product.find(:all, params: { limit: 10 })
    @webhooks = ShopifyAPI::Webhook.find(:all)
  end
end
```

しかし、このままではエラーとなってしまうので、以下のように修正が必要です。

```rb
# frozen_string_literal: true

class HomeController < ShopifyApp::AuthenticatedController
  def index
    @products = ShopifyAPI::Product.find(:all, params: { limit: 10 })
    @webhooks = ShopifyAPI::Webhook.find(:all)
  end
end
```

`ShopifyApp`モジュールから`AuthenticatedController`を継承させます。

## 8. Polarisのインストール

`Polaris`とはShopifyが公式で公開しているUIコンポーネントです。
こちらのコンポーネントを使うだけで、アプリのUIをすっきりと構築出来るので使っていきます。
[Polaris公式サイト](https://polaris.shopify.com/)

`yarn`を使ってインストールします。

> `yarn`がない場合は、`brew install yarn`をしておきましょう

```
$ yarn add @shopify/polaris
```

## 9. `hello_react.jsx`

すでに作成されている`hello_react.jsx`をそのまま使っていきます。
`app/javascript/packs/hello_react.jsx`に`Polaris`を適用させます。
詳細な使用方法は[Polaris](https://polaris.shopify.com/components/get-started#navigation)の公式を確認ください。
以下は`Polaris`が読み込まれていることを確認する程度のviewをレンダリングするようにしています。

```jsx
import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
import {AppProvider, Page, Frame, Button} from '@shopify/polaris';
const Hello = props => (
  <AppProvider apiKey={props.api_key}>
    <AppProvider >
      <Frame>
        <Page title="Test App">
          <Button onClick={() => alert('Button clicked!')}>Alert button</Button>
        </Page>
      </Frame>
    </AppProvider>
  </AppProvider>
)
// Render component with data
document.addEventListener('DOMContentLoaded', () => {
  const node = document.getElementById('hello-react')
  const data = JSON.parse(node.getAttribute('data'))
ReactDOM.render(<Hello {...data} />, node)
})
```

## 10. `embedded_app.html.erb`

`app/views/layouts/embedded.html.erb`を編集していきます。
このファイルはShopifyアプリのルートとなるviewです。
このviewに`<%= javascript_pack_tag 'hello_react' %>`と`<link rel="stylesheet" href="https://sdks.shopifycdn.com/polaris/3.13.0/polaris.min.css" />`を追記します。

追記したものは以下

```rb
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <% application_name = ShopifyApp.configuration.application_name %>
    <title><%= application_name %></title>
    <%= stylesheet_link_tag 'application' %>
    <link rel="stylesheet" href="https://sdks.shopifycdn.com/polaris/3.13.0/polaris.min.css" />
    <%= javascript_include_tag 'application', "data-turbolinks-track" => true %>
    <%= javascript_pack_tag 'hello_react' %>
    <%= csrf_meta_tags %>
  </head>

  <body>
    <div class="app-wrapper">
      <div class="app-content">
        <main role="main">
          <%= yield %>
        </main>
      </div>
    </div>

    <%= render 'layouts/flash_messages' %>

    <script src="https://cdn.shopify.com/s/assets/external/app.js?<%= Time.now.strftime('%Y%m%d%H') %>"></script>

    <%= content_tag(:div, nil, id: 'shopify-app-init', data: {
      api_key: ShopifyApp.configuration.api_key,
      shop_origin: ("https://#{ @shop_session.url }" if @shop_session),
      debug: Rails.env.development?
    } ) %>

    <% if content_for?(:javascript) %>
      <div id="ContentForJavascript" data-turbolinks-temporary>
        <%= yield :javascript %>
      </div>
    <% end %>
  </body>
</html>
```

## 11. `index.html.erb`

`app/views/home/index.html.erb`を変更します。
generate時には、`<%= asset_path('favicon.ico') %>`このような記述があるかと思うのですが、エラーとなるため、削除し、以下のようにしています。

```rb
<% content_for :javascript do %>
  <script type="text/javascript">
    ShopifyApp.ready(function(){
      ShopifyApp.Bar.initialize({
        title: "Home"
      });
    });
  </script>
<% end %>
<%= content_tag :div,
  id: "hello-react",
  data: {
    name: 'Person',
    products: @products
}.to_json do %>
<% end %>
```

## 12. foremanの設定

`foreman`とは、`Procfile`という設定ファイルを読み取り、複数のプロセスを管理することが出来るツールです。

```
// foremanをインストール
$ gem install foreman

// Procfileの作成
$ touch Procfile
```

作成した`Procfile`を以下のようにしましょう。

```
web: bundle exec rails s
webpacker: ./bin/webpack-dev-server
```

ngrokも同時に起動させたい場合は、以下のようにします。

```
web: bundle exec rails s
webpacker: ./bin/webpack-dev-server
ngrok: ngrok http -subdomain=shopifyapp 5000
```

## 13. `webpacker.yml`

`config/webpacker.yml`を変更します。
`development` > `dev_server`セクションにある、`https`、`host`、`port`を以下のようにします。

```yaml
development:
  dev_server:
    https: true
    host: 0.0.0.0
    port: 8080
```

## 14. 起動

ここまで出来たら、以下のように起動します。

```
$ foreman start
```

## 15. 開発用のストアを作成

Shopifyのパートナーアカウントへログインし、`Development Stores`からストアを作成します。
作成後、`Apps`より、作成したアプリの詳細ページへ移動し、`App actions` > `Install on development store`で先ほど作成した、開発用のストアにアプリをインストール出来ます。

インストールしたら、開発用のストアにログインし、`Apps`からアプリを確認することが出来ます。