My Day One

毎日東京の隅っこでコードを書いているエンジニアのブログです。

Herokuの代替サービスであるrender.com でRailsアプリをデプロイする

本記事の内容

  • Herokuの代替サービスになりうる render.com を使ったデプロイの方法をまとめています
  • Railsで作成した簡単なCRUD機能を搭載したアプリを render.com にデプロイするまでの手順を説明します
  • Redisなどを使った実装や設定は含まれていないので、ご了承ください

前提

  • 何らかのRailsアプリが開発環境で正しく動作するようになっている
  • RailsアプリのRDBMSPostgreSQLを使っている
  • render.com へのアカウント登録が済んでいる
  • 開発している言語やフレームワークのバージョンは、Ruby 3.1.2、Rails 6.1.6

render.com とは

Herokuと似た、WebアプリやWebサイトなどを簡単にWeb上に公開できるツールの1つです。render.com のサイトでは Render vs Heroku にあるように、Herokuをかなり意識したサービスになっています。 この比較のページでは、Herokuよりも簡単でフレキシブル、その上料金も安いよ!というような内容が書かれています。

後で詳しく書きますが、基本的にはアプリケーション側のコードを少し書き換えて、ポチポチと設定していくだけでアプリを本番環境に反映することができる素敵なサービスです。

細かいHerokuとの比較は、日本語で書かれたこちら の記事がとても詳しくて分かりやすいので、興味のある方はご覧ください。

render.com の料金体系

2022年9月時点での情報ですが、$0 (無料)から利用できます。 Webサイトや基本的な構成のWebアプリであれば、お金のことを気にせず個人開発のアプリのデプロイなどに使うことができます。

ただ、無料の場合はいくつか気を付けなくてはならない点があります。 1つ目は、アプリケーションが非アクティブの状態が15 分間続くと自動的に停止され、次の新しいリクエストが来た時に再開する、という仕組みになっており、これが起きると、ページにアクセスして20-30秒後にレスポンスが返ってくるようになってしまいます。これはさすがに遅すぎてよくないので、ひとまず個人開発のポートフォリオを作っていて、本番環境にデプロイを試したい、というレベルでなければ有料にした方が良いと思います。(特にユーザーがすぐについてほしいと思っている場合など)

2つ目は、デプロイまでにかかる時間が有料に比べて遅いということ。ちゃんと計測したわけではないですが、無料の場合、ものすごく簡素なRailsアプリをデプロイするのに4-5分かかるのに対して有料にすると2分程度でデプロイまでされていましたので、開発上のストレスという点でも有料の方が良いです。

3つ目は、これはデータベースを使うWebアプリに限った話になるのですが、PostgreSQLの無料期間は3ヶ月であり、それを超えると月$7 からの有料プランにアップグレードする必要があります。

無料でWebサイトやWebアプリを簡単にWeb上に公開できる!という点は確かにそうなのですが、いくつかの条件付きで、という観点は頭に入れておく必要があります。

有料プランを使った場合でも、2022年9月時点でのHerokuの有料版の最安値と比較すると、render.com の方が安いと思いますので、料金面でも若干お財布に優しいサービスであると思います。 (HerokuはDyno + Heroku Postgres、render.comは Services + PostgreSQLの最安値プランの合計値の比較)

Heroku render.com
$7 + $9 = $16 $7 + $7 = $14

と、ここまでは render.com の紹介を主にしてきましたが、次の節からはいよいよデプロイ手順を説明します。 基本的にはドキュメントの通りにやれば良いのですが、初心者の方でも分かりやすいようにできるだけ丁寧に説明していきます。

render.comを使ったデプロイ手順

ここからは、render.com にアカウント登録を済ませているという前提で話を進めていきますので、もしまだ登録されていない方がいましたら先に登録をお願いします。

render.com にWebアプリケーションをデプロイする場合、Web Serviceの作成とデータベースの作成をする必要があります。そのため、設定の内容を2つのパートに分けて説明します。

render.com 側の設定(Web Serviceの作成)

まずはWeb Serviceの作成です。

はじめに、render.com のDashboardに進みます。右上にある+Newのボタンを押して、Web Serviceを選択します。

すると、GitHubなどと連携するためのページに進むので、GitHubとの連携をして、対象のリポジトリを選びます。

対象のリポジトリについては全てを対象にすることもできますし、自分で選択したもののみを設定することもできます。 以下の画面は、私のGitHubのページの設定です。1つのリポジトリのみを設定しています。

対象のリポジトリを選択したら、いくつか必要な設定をすることになりますので、以下を参考に入力してみてください。

  • Name: 何でもいいですが、わかりやすい名前にしておきましょう。こちらは後から変更可能です
  • Environment: Railsのアプリをデプロイする前提なので、Rubyを選びます
  • Region: 現状、東京リージョンがないのでシンガポールを選びましょう。(2022年に東京リージョンも追加される予定とのこと)
  • Branch: デプロイしたいブランチを設定できます。mainで良いと思いますが、とりあえず別ブランチで試したいという方は別ブランチを設定すればOKです。あとから変更可)
  • Build Command: 一旦デフォルトのままで問題ありません。
  • Start Command: こちらも一旦デフォルトのままで問題ありません。
  • Advanced: 環境変数などの設定ができます。こちらも後から変更可能です。(最低限、master_keyの設定は後で必須となります)

設定画面のイメージは以下です。

いきなりお金がかかると嫌という方もいると思いますので、ひとまずfreeプランを選択して先に進みます。

問題なくWeb serviceが作成されたと思いますが、最後に、Railsのアプリケーションを本番環境でデプロイする際に必要な RAILS_MASTER_KEY を設定しておきます。

先ほどのAdvancedの箇所でも設定できるので、すでにやっている方は読み飛ばしてください。

Dashboardに戻ると、先ほど作成したWeb Serviceが一覧に表示されているかと思いますので、そちらをクリックします。

遷移した先のページの真ん中あたりにずらっとタブが並んでいて、その中のEnviromentをクリックします。

Environmentをクリックすると、本番環境用の環境変数の設定ができる画面に遷移するので、RAILS_MASTER_KEY の値に config/master.key に書かれている値を設定し、Save Changesをクリックします。(これを設定しておかないと、デプロイができません)

ひとまず、ここまでで、render.comのWeb Serviceの作成は終了となります。

render.com 側の設定(データベース作成)

続いて、データベースの作成と設定をします。こちらも先ほどと同様に render.com の画面から行います。

先ほどのWeb Serviceの作成と同様に、Dashboardの右上にある +New ボタンを押して、PostgreSQLを選択します。

すると、以下のような画面に遷移します。

入力項目は

  • Name: render.com 上で表示されるDBの名前です。後で変更できます。
  • Database: PostgreSQL の dbnameを設定します。
  • User: PostgreSQL接続時に必要なユーザー名です。
  • Region: Web serviceと同じ項目です。シンガポールを選択しましょう。
  • PostgreSQL Version: PostgreSQLのバージョンです。デフォルトで14になっていますが、必要に応じて変更しましょう。

注意事項として、Database, User、PostgreSQL Versionはあとから変更できないはずなので、設定時には気をつけましょう。もし間違えてしまった場合は、データベースを一度消して、再度作り直せば問題なく修正できます。

上記の必要な情報を入力していき、Create Database ボタンを押します。少し待つとstatusがAvailableになり、データベースが使えるようになります。

これで、データベースの作成も完了しました。

ここまでは、render.com側でRailsアプリをデプロイするための準備をしましたが、ここから先はRailsアプリ側に必要な設定を行なっていきます。一部コードを書き換える必要があるので、その点はご注意ください。

Railsアプリ側の設定

Railsアプリ側の設定については、ドキュメントを読みながら進めていくこともできます。

基本的にドキュメントを翻訳した形になりますが、この記事でもRailsアプリ側の設定内容を説明していきます。

1. config/database.ymlの編集

  • productionのセクションに行き、DATABASE_URLの環境変数を使うようにします。
production:
  # 他の記述がある場合はそれもそのまま残しておく
  <<: *default
  url: <%= ENV['DATABASE_URL'] %>

2.config/puma.rbの編集

  • workers ENV.fetch("WEB_CONCURRENCY") の記述を追記します。(コメントアウトを外して数値を4に変更します)
  • preload_app! の記述を追記します(コメントアウトを外します)
(中略)
workers ENV.fetch("WEB_CONCURRENCY") { 4 }
(中略)
preload_app!

3.config/environments/production.rbの編集

  • RENDER環境変数(これは常にRenderにある)が存在する場合、パブリックファイルサーバーを有効にします。
config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? || ENV['RENDER'].present?

4.ビルド用のscriptを作成する

  • アプリのビルドに必要なコマンドを実行できるように設定します。
  • bin/render-build.sh を作成します(binフォルダ配下にrender-build.shというファイルを作成)
  • bin/render-build.sh の内容は以下の通りです。
#!/usr/bin/env bash
# exit on error
set -o errexit

bundle install
bundle exec rake assets:precompile
bundle exec rake assets:clean
bundle exec rake db:migrate
  • 以下のコマンドで、bin/render-build.sh の実行権限を設定しておきます。
chmod a+x bin/render-build.sh
  • 上記の内容を全て変更し、Gitリポジトリの対象ブランチにpushすれば、renderを使ってデプロイが始まります。

数分待ち、Dashboard内のWeb serviceの欄にDeploy Succeeded という表示があれば完了です!🎉

デプロイが失敗した時のエラー(私の場合)

私は最初にデプロイした時にエラーになり、 ! Unable to load application: LoadError: cannot load such file -- net/imap のようなエラーが出たのですが、こちら の記事と同じ対処法で解決しました。

Blueprintsを使ったデプロイについて

実は、render.com で Webアプリをデプロイするには、先ほど説明したダッシュボードを使用してサービスを手動で設定する方法と、render.yaml ファイルでリポジトリ内のサービスを宣言する方法との 2 つがあります。

この後者の方法を使うために利用されるのがBlueprintsという機能です。

これを使うメリットとしては

  • アプリケーションの構成をわかりやすくひとまとめにすることができる
  • Render.com にどのような構成のサービスを作成するかを管理することができる

という点が挙げられるでしょう。Infrastructure as code(IaC) を render.com で実現できるということですね。便利です。

Blueprintsを利用する手順は以下の通りで、とてもシンプルです。

  • ルートディレクトリに render.yaml という名前のファイルを作成する。(このファイルには、RailsのWeb サービスと、アプリケーションで使用されるデータベースに関する情報が含まれます)
  • render.yamlを以下のように編集して、mainブランチに pushしておく
databases:
# mysiteは設定した際の内容を確認して書き換える
  - name: mysite
    databaseName: mysite
    user: mysite

services:
  - type: web
    name: mysite
    env: ruby
    buildCommand: "./bin/render-build.sh"
    startCommand: "bundle exec puma -C config/puma.rb"
    envVars:
      - key: DATABASE_URL
        fromDatabase:
          name: mysite
          property: connectionString
      - key: RAILS_MASTER_KEY
        sync: false
  • pushしたら render.com の DashboardからBlueprintのページに移動して、New Blueprint Instance ボタンをクリックします。

対象のリポジトリを選択し、デプロイ ウィンドウで、RAILS_MASTER_KEY の値を config/master.key ファイルの内容に設定した上で、Update Existing Resourcesをクリックするとデプロイがスタートします。

こんな感じで、単にデプロイするだけであればそんなに大きな労力を割くことなく進めることができるため、Herokuの代替サービスには確かになるなと思いました。

長くなってしまったので今回の記事はここまでにして、次回は render.com を使ったカスタムドメインの設定を書きたいと思います。

【Rails】gem deviseを使ってメール認証を実装した時に落ちるテストの対応

本記事の内容

deviseを使ってメール認証の機能を追加した際に、既存のテストが落ちてしまうという事象に遭遇しました。 今回の記事はそのテストが落ちないように修正した際に、どういった対応をしたのかをまとめたものになります。

状況

  • gem deivseを使ってログイン機能はすでに実装済
  • ログイン機能に関してのrpsecのコードも存在している(before { sign_in user } などのコード)
  • ログイン機能は実装していたが、ユーザーのアカウント登録時にメール認証の機能をつける必要があると判断したため、その機能を追加した
  • メール認証の機能を追加したところ、ログインが関係しているテストが全て落ちるようになった
  • Rubyのバージョンは3.1.2、Railsのバージョンは6.1.6

テストを走らせた時のエラー内容①

Failure/Error: = link_to t('devise.mailer.confirmation_instructions.action'), confirmation_url(@resource, confirmation_token: @token)
      
      ActionView::Template::Error:
        Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true

エラーの原因①

エラーメッセージに書いてある通りではあるんですが、リンク先となるhostがないため、hostパラメータを指定するか、default_url_options[:host]を設定するか、:only_pathをtrueに設定するなどする必要があるようです。

解決策①

エラーメッセージを検索してみるといくつかそれらしい記事が出てきました。 下記の記事にある通り、config/environments/test.rb にhostに関しての情報を追記することで、上記のエラーはなくなりました。

config.action_mailer.default_url_options = { host: "localhost", port: 3000 }

k-koh.hatenablog.com

これで、一件落着、めでたしめでたし...と思ったが、まだテストを走らせてもエラーが出ていたのでそちらも調査...。

テストを走らせた時のエラー内容②

Failure/Error: expect(response).to have_http_status(:ok)
       expected the response to have status code :ok (200) but it was :found (302)

エラーの原因②

ここのエラーが出ている箇所は、ログインした後のユーザーがあるページに遷移した際、そのページが正しく表示されているかをテストしているんですが、200ではなく302(リダイレクト )してしまっているようです。 リダイレクト するということは、そもそもテストデータ上ではログインがうまくいっていないためと思われます。

また、ログイン周りがうまくいかなくなっていることが原因で、データの作成や更新などのテストも複数落ちていました。

解決策②

こちらもたまたま、ほとんど答えが書いてある記事を見つけ、userをログインさせる前に、ユーザーを認証させるためのコードを書く必要がありました。

<変更前>

before { sign_in user } 

<変更後>

# 複数行になったのでbefore do ~ endを使う
before do
  user.confirm # ここを追加
  sign_in user
end

qiita.com

これで、テストも全て通るようになりました!

エラーメッセージをきちんと読んで検索する、ということで今回は解決に至りました👍

標準入出力・ファイル・リダイレクト・パイプについて

はじめに

この記事は私の知識の整理のために、標準入出力・ファイル・リダイレクション・パイプについてまとめたものです。 webアプリの開発をするときにはそこまで意識しないことではありますが、開発者としては抑えておくべき基礎なので、それを自分なりに、他人に説明するくらいのスタンスでまとめてみました。 間違いなどあればご指摘ください!それでは書いていきます。

標準入力

これは、コンピューター上で実行されているプログラムが、何も特別な指定がされていない場合に利用するデータの入力元のことを言います。 少し分かりにくいと思うので、コマンドラインを例にとると

$ ls

とすると、結果が返ってきますよね。この ls が標準入力です。

標準出力

先ほどの標準入力(ls)を入力してEnterキーを押すと

Applications
Creative Cloud Files
Desktop
Documents
Downloads

みたいな感じでその結果が返ってきます。これが、標準出力です。 標準出力は、標準入力がプログラムに渡り、そこから出力される結果ということですね。

10 + 1 = 11 みたいな式があるとしたら、 10と1が標準入力、 10 + 1という演算がプログラム、 11が標準出力 といった具合です。

標準エラー出力

主にプログラムのエラーを表示するために使用されます。 ls コマンドで存在しないファイルを指定した場合、下記のようなエラーメッセージが表示されます。このエラーメッセージは標準エラー出力に表示されています。

$ ls /aaaaaa
ls: /aaaaaa: No such file or directory

ファイル

コンピューター上で管理される情報の単位のこと。ファイルの名前は人間が識別しやすいように名前がつけられています。sample.txthoge.html のようなものがそれに当たります。 ファイルはそれ単体でもコンピューター上に存在するが、XX関連のファイルをまとめておきたい、という場合にフォルダという単位でファイルを格納することもできます。

また、ファイルは主に、プログラムファイル、データファイルに分かれます。 プログラムファイルはJavascriptRubyなどで書かれたファイル(例えば sample.js sample2.rb など)を指し、データファイルはpngやjpgの画像ファイルなど、それ自体はコンピューター上で実行されず、プログラムによって読み込みまれるようなものを指します。

フォルダも管理する上での単位という意味ではファイルと同じですが、フォルダは「フォルダの中にファイルを入れることができ、かつ、フォルダも入れることができる」というのが1つの特徴です。

テキストファイル・バイナリファイルという分類もあり、テキストファイルは人間が識別できる文字や数字で書かれたファイルのことで、バイナリファイルは人間では読めない形式(コンピューターが読む前提の形式)でのファイルのことになります。

リダイレクト

標準入力、標準出力先を変更する機能のこと。 例えば cat コマンドは

$ cat file_name

のようにしてfileの中身を表示しますが、その出力先を変えたり、標準入力の元ファイルを変更したりするのに使うことができます。

リダイレクトは主に >< を使用して入出力をコントロールします。

例えば、ls -l コマンドで表示できる内容を、コマンドライン上に出力するのではなく、result.txt に送りたい、という場合は

ls -l list.txt

とします。これで、ls -l の結果が result.txt に全て入るようになります。書き込まれたかどうか確認するには

cat result.txt

で確認できます。

ただし、標準エラー出力

$ ls /aaaaaa > list.txt
ls: /aaaaaa: No such file or directory

のように単純にリダイレクトしても、コマンド上に表示されてしまうので

$ ls /aaaaaa 2> list.txt

のように 2> をリダイレクトに使うことでファイル内に格納します。

また、「コマンドの結果とエラーメッセージを別々のファイルに出力したい」というケースもあるかと思いますが、その場合は

$ ls /aaaaaa > list.txt 2> error.txt

のようにします。これは、実行結果は list.txt へ、エラーは error.txt へと送られるコマンドです。1行で書けて便利ですね!

コマンドの結果とエラーメッセージを合わせて1つのログファイルにしたい!というときは

$ ls / aaaaaa > result.txt 2>&1

のようにすることで、1つのファイルにまとめて出力できるようになります。

コマンドの意味合いとしては、最初の > が標準出力先を result.txt に設定するためのコマンド、次の 2>標準エラー出力の設定先を設定するためのコマンド、最後の &1 が標準出力と同じファイルへ出力先を指定するためのコマンド、といった具合です。2>&1 で1つのセットとしても良いかもしれません。これも便利です。

リダイレクトをすると、指定したファイル名と同じファイル名がある場合には、特別な設定を何もしなければ、その内容が上書きされてしまいます。

$ echo 10000 > number.txt
$ echo 99999 > number.txt

として、catで内容を表示すると

$ cat number.txt
99999

となり、元の10000は上書きされてしまいます。

上書きを防ぐには >> を使って、ファイルの末尾に追加する、というような処理を使います。

また、シェルのオプションで noclobber というオプションを使うとファイルの上書きの禁止ができるので、それを設定して上書きをさせない設定にするというのも1つの手段です。

パイプ

コマンドは1つ入力して出力させておしまいではありません。複数コマンドをつなげて、より複雑なこともできます。例えば、/binフォルダの中にあるファイルの、ファイルサイズが大きい順の3つを取得する、というようなこともできたりします。

それを実現するために必要なのが、パイプという機能です。

まずは例を見てみましょう。

$ ls -l / > sample_list.txt
$ less sample_list.txt

これでも結果を表示することはできますが、1行で書く方法でパイプを使用します。

$ ls -l | less

この例を見れば想像がつくかもしれませんが、パイプ(記号で表すと | )によって、前のコマンドの結果を次のコマンドに渡すことができるということです。実行結果を渡せるのは便利ですね。

このパイプを、フィルタと呼ばれる標準出力を入力として受け取り、標準出力に出力するコマンドと一緒に使うことで、/binフォルダの中にあるファイルの、ファイルサイズが大きい順の3つを取得する、ということを実際に書いてみます。

使うコマンドは3つで、 du、sort、head のみです。

  • duコマンド→-kオプションを渡すことで、ファイルのサイズをキロバイト数で表示する
  • sortコマンド→昇順(今回は小さい順)に並べる。デフォルトはアルファベット順だが、-nオプションをつけることでサイズ順に並べることができる。-rオプションをつけると逆順になる
  • headコマンド→上から順に取得した結果を表示する -n 3のようにオプションを渡すと上から3つを取得できる

という特徴を使ってコマンドを書くと

$ du -k /bin/* | sort -n -r | head -n 5

となり、出力結果は

720 /bin/ksh
368 /bin/zsh
340 /bin/bash
260 /bin/tcsh
260 /bin/csh

となります。キロバイト数の大きい順に表示され、やりたいことも達成できました。

コマンドラインはあまりちゃんと勉強してこなかったので、勉強すると基礎でも奥が深いなと感じました。

UNIX/Linuxについてまとめてみる

半年で自走できるバックエンドエンジニアになるためにアウトプット用のブログを作りました。 一応、数年コーダーやフロントエンドの開発に携わっていたこともあるので、全くの初心者ではありませんが、壊滅的にネットワークやインフラ、バックエンドのスキルがないため、勉強し始めました。

今回はUNIX/Linuxについてまとめていきます。

UNIXとは?

  • OSの一種である。
  • WindowsUNIXの2つのOSがあるが、大雑把にいうと、違いはGUIがメインかどうか。
  • UNIXのOSのベースはCUI
  • UNIXの中心にはカーネルがある
  • カーネルはCPU、メモリ、ハードウェア割り込みなど、ハードウェアに関することを管理
  • カーネルが中心となり、様々なソフトやドライバ、シェルなどが動いている
  • ちなみにシェルはコマンドインタプリタともいう

ファイルシステム

$ cd hoge

マウント

  • UNIXの場合はファイル構造が全てルートディレクトリから始まる
  • そのため、CD-ROMなどのファイルを指定する場合、ディレクトリを関連づけることでファイル構造を表現する
  • mnt/cdromに対して/develop/romを関連付けるようなイメージ
  • Windowの場合はこの概念がない

mnt/cdromに対して/develop/romを関連付けるようなイメージ、という表現はとてもしっくりきた。今までなんとなくみていたものが繋がった感じ。

シェル

  • キーボードからの入力を受けてそのコマンドを解釈、実行するプログラム
  • ユーザーとカーネルの間に立つ仲介役のようなもの
  • bash,zshなど様々な種類がある
  • どれを使用すべきというのはない
  • 過去に入力したコマンドを記憶するヒストリ機能というものがある
(base) MyMacBookpuro:~ username$ history 5
  542  ssh name@100.00.0.10
  543  ssh-copy-id -i ~/.ssh/id_rsa.pub name@100.00.0.10
  544  ssh-copy-id -i ~/.ssh/id_rsa.pub name@100.00.0.10
  545  ssh-copy-id -i ~/.ssh/id_rsa.pub name@100.00.0.10 -p 3000
  546  history 5
$ !542 

のようにすると一番上に表示されているコマンドを実行できるらしい。こんな機能もあるんだな。

ワイルドカード

  • *(アスタリスク)を使うことで、hogeで始まるファイル名とかを検索できたりする
$ ls hoge*

こうすると

hoge001
hoge002

のようなファイルを検索することができる

パイプ

  • あるコマンドの出力結果を別のコマンドの入力として使う機能 例えば ls コマンドで以下のような結果が出る場合
$ ls

abcd
abbc
acdc

dが入っているものを検索したいとしたら

$ ls | grep d

abcd
acdc

ls コマンドで出力したものを grep コマンドに渡すことで絞り込みを行うことができるようになる。 これは ls の後ろにある |のおかげでそれができるようになる。

シェル変数と環境変数

  • シェル変数は実行中のシェルの中で有効なもので、環境変数は新しいシェルや別のコマンドでも使える
$ HOGE=fuga

のようにするとシェル変数をセットでき、

$ export HOGE=fuga

のようにすると環境変数にセットできる。

なんかいつも何も考えずにexport PATH .... とやっているのもこれだったのだな。なるほど…

ファイルやディレクトリの所有権

  • ファイル、ディレクトリにはアクセス権が存在する
  • 操作するユーザーの立場によって、ファイルやディレクトリの操作を制限することができる

chmod コマンドはそれを設定するためのコマンド

$ chmod [-f] [-R] MODE FILE

のように使う。FILEに指定したファイルやディレクトリへのアクセス権が変更され、変更内容はMODEで受け付けるようになっている MODEは3桁の8進数で表示することができ、一番上の桁から順に、所有者のアクセス権、グループのアクセス権、その他のアクセス権、となっていて

例えばSSH接続する際によく出てくる

$ chmod 600 id_rsa

のような記述は

  • 所有者のアクセス権が6=読み込み権と書き込み権がある
  • グループ、その他はそれぞれ0=権限なし
  • 対象はid_rsa のように指定しているということ。

長くなってしまったので、一旦この辺りで。勉強になった。