いざRuby on Jetsを試したらハマったことをメモしておく（jets newからdeployまで）

# はじめに

同僚が[Ruby on Jets](https://rubyonjets.com/)に心酔していたので、いざ試してみよう、と思ったら思いの外ハマったためメモを残しておくことにしました。Jetsのドキュメント[Quick Start](https://rubyonjets.com/quick-start/)を進めていくところでのハマりどころなので、あわせてご覧くださいませ。

## 試した環境

```
$ sw_vers
ProductName:	Mac OS X
ProductVersion:	10.14.5
BuildVersion:	18F132

$ ruby -v
ruby 2.6.4p104 (2019-08-28 revision 67798) [x86_64-darwin18]

$ jets -v
2.1.2
```

# tl;dr

* [Lambdaで動くrubyバージョン](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-ruby.html)で開発しよう（2.5系）
* Macで発生するmysql2のインストールエラーはbrewでインストールされたopensslのlibディレクトリがライブラリパスとして認識されていないだけだから`export LIBRARY_PATH=$LIBRARY_PATH:/usr/local/opt/openssl/lib/`しとくと良いよ
* デフォルトではDBにMySQLが指定されるので、イヤだったら`--database=postgresql`オプションをつけて`jets new`しよう
* `jets new`実行時にAWSとの通信があるので、Jetsで利用するためのIAMユーザーを作成して`aws configure --profile yourname`でプロファイル作って`AWS_PROFILE=yourname jets new ...`みたいに環境変数でプロファイルを指定しておこう
* デプロイ時にも`AWS_PROFILE=yourname jets deploy`って感じで、いずれにしても上記で作ったIAMユーザーを使う

# `jets new demo`実行時

## mysql2 gemがインストールできない

```
ld: library not found for -lssl
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [mysql2.bundle] Error 1
```

毎度恒例（？）のmysql2 gemがインストールできない問題。デフォルトでJetsはMySQLを利用するらしい。Jets 2.1.2だとmysql2 0.5.2をインストールするようなので、個別にgem installしておくことにした。

```
gem install mysql2 -v '0.5.2' -- --with-ldflags=-L/usr/local/opt/openssl/lib --with-cppflags=-I/usr/local/opt/openssl/include
```

bundle installがこけてもプロジェクトディレクトリ自体は作成されるが、bundle install後に後続で処理が続くようなので、エラーが発生したら一旦できかけたディレクトリを削除して、もう1回`jets new [Project Name]`するのがオススメ。

### （追記）

デフォルトではmysqlが選択されるが、以下のように`jets new`にdatabaseオプションを渡せばpostgresqlを指定することもできる。

```
$ jets new demo --database=postgresql
```

`--no-database`オプションを渡せばDBのセットアップを含めないことも可能。

```
$ jets new demo --no-database
```

参考: https://rubyonjets.com/reference/jets-new/

## `Aws::STS::Errors::InvalidClientTokenId`が発生する

（もしくは`INFO: You're missing AWS credentials. Only local services are currently available`というメッセージが表示される）

```
         run  bundle exec jets webpacker:install from "."
bundler: failed to load command: jets (/Users/mah_lab/.anyenv/envs/rbenv/versions/2.6.4/bin/jets)
Aws::STS::Errors::InvalidClientTokenId: The security token included in the request is invalid.
```

STS（AWS Security Token Service）のエラーなので、AWS周りの設定に問題があるのだろう、という見立て。まずはaws-cliのバージョンを確認。（古い場合は`pip install awscli --upgrade --user`でアップデートしておく）

```
$ aws --version
aws-cli/1.16.150 Python/3.7.3 Darwin/18.6.0 botocore/1.12.140
```

続けて`aws configure`で、Jetsで使用するIAMの設定を行う。[Jetsのドキュメントに最小限のIAMポリシーを持つグループの設定について解説](https://rubyonjets.com/docs/extras/minimal-deploy-iam/)があるので、まずは例にならってグループの作成を行う。

```
$ aws iam create-group --group-name Jets
$ cat << 'EOF' > /tmp/jets-iam-policy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "apigateway:*",
                "cloudformation:*",
                "dynamodb:*",
                "events:*",
                "iam:*",
                "lambda:*",
                "logs:*",
                "route53:*",
                "s3:*"
             ],
            "Resource": [
                "*"
            ]
        }
    ]
}
EOF
$ aws iam put-group-policy --group-name Jets --policy-name JetsPolicy --policy-document file:///tmp/jets-iam-policy.json
```

そしてグループにユーザーを割り当てる（ユーザー名は任意でOK）。

```
$ aws iam create-user --user-name jets
$ aws iam add-user-to-group --user-name jets --group-name Jets
$ aws iam create-access-key --user-name jets
```

取得したクレデンシャルを`aws configure`で設定（リージョンはお好みで）。

```
$ aws configure --profile jets
AWS Access Key ID [None]: 使用するIAMのアクセスキー
AWS Secret Access Key [None]: 使用するIAMのシークレットキー
Default region name [None]: ap-northeast-1
Default output format [None]: json
```

作成したプロファイルを指定して`jets new`を実行。

```
$ AWS_PROFILE=jets jets new demo

（中略）

         run  bundle exec jets webpacker:install from "."
      create  config/webpacker.yml
Copying webpack core config
      create  config/webpack
      create  config/webpack/development.js
      create  config/webpack/environment.js
      create  config/webpack/production.js
      create  config/webpack/staging.js
      create  config/webpack/test.js
Copying .postcssrc.yml to app root directory
      create  .postcssrc.yml
Copying .babelrc to app root directory
      create  .babelrc
Installing binstubs
         run  bundle binstubs webpacker from "."
      append  .gitignore
Installing all JavaScript dependencies

（以下、延々とJS周りのセットアップが続く）

================================================================
Congrats 🎉 You have successfully created a Jets project.

Cd into the project directory:
  cd demo

To start a server and test locally:
  jets server # localhost:8888 should have the Jets welcome page

Scaffold example:
  jets generate scaffold post title:string body:text published:boolean
  jets db:create db:migrate

To deploy to AWS Lambda, edit your .env.development.remote and add a DATABASE_URL endpoint.
Then run:

  jets deploy
```

## `demo`ディレクトリに移動して、`jets server`を起動

ハマることなく動いた。

![スクリーンショット 2019-08-31 11.46.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5877/34d12d68-2a43-0914-5c29-8d30b28b95f6.png)

# scaffoldからの流れ

```
$ jets generate scaffold post title:string
      invoke  active_record
      create    db/migrate/20190831024645_create_posts.rb
      create    app/models/post.rb
      invoke  resource_route
       route    resources :posts
      invoke  scaffold_controller
      create    app/controllers/posts_controller.rb
      invoke    erb
      create      app/views/posts
      create      app/views/posts/index.html.erb
      create      app/views/posts/edit.html.erb
      create      app/views/posts/show.html.erb
      create      app/views/posts/new.html.erb
      create      app/views/posts/_form.html.erb
      invoke    helper
      create      app/helpers/posts_helper.rb

$ jets db:create db:migrate
Created database 'demo_development'
Created database 'demo_test'
== 20190831024645 CreatePosts: migrating ======================================
-- create_table(:posts)
   -> 0.0717s
== 20190831024645 CreatePosts: migrated (0.0718s) =============================
```

特にハマることもなくscaffoldされた画面が表示された。

![スクリーンショット 2019-08-31 11.49.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5877/2eb8ab49-7e60-e527-f305-bd4aed28255e.png)

なんとなく`jets console`でデータの確認もしてみたが、普通にRailsを使うのと同じようにコンソールを扱うことができる。

```
$ jets console
Jets booting up in development mode!
irb(main):001:0> Post.first
=> #<Post id: 1, title: "test", created_at: "2019-08-31 02:49:18", updated_at: "2019-08-31 02:49:18">
```

# `jets deploy`

## Lambdaで使えるrubyバージョンは2.5系ですよ

```
$ AWS_PROFILE=jets jets deploy
Deploying to Lambda demo-dev environment...
Building CloudFormation templates.
Deploying CloudFormation stack with jets app!
12:19:55PM CREATE_IN_PROGRESS AWS::CloudFormation::Stack demo-dev User Initiated
12:19:58PM CREATE_IN_PROGRESS AWS::S3::Bucket S3Bucket
12:19:59PM CREATE_IN_PROGRESS AWS::S3::Bucket S3Bucket Resource creation Initiated
12:20:20PM CREATE_COMPLETE AWS::S3::Bucket S3Bucket
12:20:21PM CREATE_COMPLETE AWS::CloudFormation::Stack demo-dev
Stack success status: CREATE_COMPLETE
Time took for stack deployment: 31s.
You are using Ruby version 2.6.4 which is not supported by Jets.
Jets uses Ruby 2.5.3.  You should use a variant of Ruby 2.5.x
```

「JetsはRuby 2.5.3を使うよ」と言われるので、Ruby 2.5.3を使うようにする。

```
$ rbenv local 2.5.3
$ bundle install -j4
```

## deploy時にもmysql2 gemのインストールで怒られる

```
（中略）
=> cd /tmp/jets/demo/cache && env BUNDLE_IGNORE_CONFIG=1 bundle install --path /tmp/jets/demo/cache/vendor/gems --without development test
F
（中略）
ld: library not found for -lssl
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [mysql2.bundle] Error 1
```

`BUNDLE_IGNORE_CONFIG`オプションがついているので、bundle configによる設定が効かない :angel: （[関連コード](https://github.com/tongueroo/jets/blob/14ec869fc304a7003a6a5ab7fba37916304804cb/lib/jets/builders/ruby_packager.rb#L57)）。

なので、よく見かけるオプションをつける付け焼き刃的な解決方法ではなく、根本的にライブラリが読み込めない問題を解決してあげる必要がある。。

具体的には以下のように`$(brew --prefix openssl)/lib`がライブラリパスとして認識されるように環境変数で設定しよう。

```
export LIBRARY_PATH=$LIBRARY_PATH:/usr/local/opt/openssl/lib/
```

何でもググって付け焼き刃で対応してはいけないという教訓である。。（[関連Issueコメント](https://github.com/brianmario/mysql2/issues/795#issuecomment-337006164)）

## deployできた・・・！

![スクリーンショット 2019-08-31 13.34.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5877/af091936-2575-ceda-d447-b22f0ee8b359.png)

## RDSの設定について

もちろんこのままだとRDBの設定ができていないので、`/posts`にアクセスするとエラーになる。

![スクリーンショット 2019-08-31 13.39.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/5877/5b6f79d9-700b-eb63-afdf-9570546b9ee0.png)

あとはRDSインスタンスを作成してDBの情報を設定するだけでハマるところはなかったので、そこまで完了したい方は以下の記事を参考に設定してみてください。

[Ruby 製サーバーレスフレームワークの Jets を検証してみたら、Rails ライクに使えていい感じだった > RDS MySQL データベース作成](https://qiita.com/gotchane/items/fd3c1e54f7bdaa4ab813#rds-mysql-%E3%83%87%E3%83%BC%E3%82%BF%E3%83%99%E3%83%BC%E3%82%B9%E4%BD%9C%E6%88%90)