Node.js 環境変数の設定
こんにちは、皆さん!
今回はNode.jsで安全に環境変数を設定する方法について紹介していきたいと思います。
- トピック:
環境変数とは?
簡単に言いますと、外部から与えられるデータのことです。直接コードの中ではそのものを書かずに他のファイルからそれを読み取ります。
なぜ環境変数を使うのか?
なぜ環境変数を安全に保護しないといけないのか?
どうやって安全にキープするのか?
process.env.API_KEY
env
の後に環境変数の名前をつければアクセスできます。
ローカルでは他のファイルに保存しておけば、アクセスできます。このファイルに関してはgitignore
しっかりとオンラインにシェアされないように
プロダクション、つまり、オンラインでは例えば、Herokuならconfig
に環境変数を保存すれば他人には見られないので安全にキープできます。
では、試してみましょう!!
おススメはそのコードをダウンロードして、この記事通りに見て、そして、ローカルやHerokuで試してみることです。
まず、コードの構造について少し説明します。
config
ディレクトリーの中にあるのが環境変数を管理する部分です。prod.js
がプロダクション、test.js
がテスト、dev.js
がローカルという形でそれぞれがそれぞれの環境の変数を管理しています。次に
index.js
ファイルで環境に応じてどのファイルのデータを返すかを決めます。
if (process.env.NODE_ENV === 'production') { module.exports = require('./prod'); } else if (process.env.NODE_ENV === 'test') { module.exports = require('./test'); } else { module.exports = require('./dev'); }
ここにあるように環境ごとにそれぞれの変数を管理しているファイルを返すのです。
あとは.gitignore
の方でローカルとテスト環境の変数が外部に漏れないようにフィルターするだけ
# モジュールはわざわざプッシュする必要はない node_modules # ローカルとテスト環境の環境変数はGithubに表示されないようにします config/dev.js config/test.js
以上で環境変数の設定は完了。そしたら、server.js
で実際にどう使うかを見てみましょう!
ここではMongooseを使う際のURLを環境変数を使い、各環境で違うデータベースにアクセスできるようにします。
まず、ローカルとテスト環境のデータベースのURLを設定します。
// dev.js module.exports = { DB_URI: "mongodb://localhost:27017/environment-variables-app" }
//test.js module.exports = { DB_URI: "mongodb://localhost:27017/environment-variables-app-test" }
次にプロダクションの方の変数も定義したいのですが、プロダクションではサーバー側の設定から環境変数がパスされてきます。例えば、Herokuでこのアプリケーションを使うのなら、そこで、変数の名前をDB_URI
とし、実際のURLを入れ、下記のようにその変数にアクセスします。
// prod.js module.exports = { DB_URI: process.env.DB_URI }
これならGithubに載せても他人から情報を盗まれませんね!
では、いよいよserver.js
内のコードを見ていきましょう!
まず、外部から必要なものをインポートしてきます。このとき、require('./config')
となっていてディレクトリーをインポートしようとしているように見えるが、実はindex.js
を認識して、そこにたどり着いているのです。
次にconst url = config.DB_URI;
で環境変数にアクセスし、MongoDBのURLを取得します。
そして、最後にサーバーをスタートします。
const express = require('express'); const mongoose = require('mongoose'); const config = require('./config'); const url = config.DB_URI; const port = process.env.PORT || 8080; // MongoDBデータベースに接続 mongoose.connect(url, function (err, res) { if (err) { console.log ('ERROR connecting to: ' + url + '. ' + err); } else { console.log ('Succeeded connected to: ' + url); } }); // サーバーをスタートする const app = express(); app.get('/', (req, res) => res.send('Hello World!')) app.listen(port, () => console.log(`Example app listening on port ${port}!`))
実際にこのサーバーをスタートすれば、コンソールで実際にどのMongoDBのサーバーに接続したかが見れます。
では、次はHerokuでどうやって設定するかです。
まずはHerokuのconfigを確認してみましょう!
$ heroku config
すると、まだ何も入れてないので、空の状態です。
HerokuでMongoDBを使おうとすると、mLabというアドオンを入れる必要があるので、それを入れてみましょう!
追加した後にもう一度heroku config
とやると、今足したmLabのURLが見れるはずです。
MONGODB_URI: mongodb://heroku_3636wvfr:ka9cqpra6f4r8g3gfk8n2la4bs@ds255797.mlab.com:55797/heroku_3636wvfr
こんな感じで出てくるのだが、今のアプリではDB_URI
という環境変数でアクセスしているので、環境変数をこの名前で新たに追加しましょう!!
下記のコマンドを入力して、configに環境変数を追加しましょう!
$ heroku config:set DB_URI=mongodb://heroku_3636wvfr:ka9cqpra6f4r8g3gfk8n2la4bs@ds255797.mlab.com:55797/heroku_3636wvfr
後ろの部分はご自身のMongoDBのURLを入れてくださいね!
ここで、またコマンドでconfigを開くと、
DB_URI: mongodb://heroku_3636wvfr:ka9cqpra6f4r8g3gfk8n2la4bs@ds255797.mlab.com:55797/heroku_3636wvfr
この内容が追加されています。
これでHerokuのサイト上でもアクセスできるようになります!!
まとめ
僕もはじめはこんなに簡単に設定できるのかと感心しました。
みなさんの役に立つことを願います!
では、また次回まで✌
記事更新はツイッターで告知するので、ツイッターの方でもフォローお願いします!
twitter.com
RspecでJSONオブジェクトの値を確認する
こんにちは、皆さん!
Railsでウェブアプリケーションを作っていく上で、その品質を保証するためにRspecは欠かせない。そして、最近ではRailsでAPIを作る人たちも増えてきている。そんなAPIなのだが、普通コントローラーがJSONオブジェクトという形でデータを返してくる。今回はそのオブジェクト内の値をチェックする方法を紹介したいと思う。
- トピック:
今回使うモデルの説明
create
アクション。
# users_controller.rb def create @user = User.create(user_params) render json: @user, status: :created end private def user_params params.require(:user).permit(:email, :password, :password_confirmation) end
ベースのテストコードは下記のようになっている。今回はここにもう一つコードを足して、JSONとして返ってきたオブジェクトのメールがもともと入れたメールと同じか確認する。
# users_controller_spec.rb describe "POST create" do it "should create a user with valid params" do post :create, params: {user: {email: "example@example.com", password: "foobar", password_confirmation: "foobar"}} expect(response).to have_http_status(:created) end end
覚えておくべきことは
- ここで使うのは
create
アクションだけであること - そのアクションではJSONオブジェクトのUserが返され、
:created
というステータスがついてくること - そのステータスはテストコードの
POST
リクエスト後に確認がされていること response.body
に返されたJSONオブジェクトの詳細が入っていること
では、実際に両方の例を見ていこう!!
うまくいかない例
describe "POST create" do it "should create a user with valid params" do post :create, params: {user: {email: "example@example.com", password: "foobar", password_confirmation: "foobar"}} expect(response).to have_http_status(:created) expect(response.body['email']).to eq("example@example.com") end end
これはいつもJavaScriptでキーを使って値を抜き出してる人からしたら、とても常識的なやり方。しかし、Rubyでは下記のように想定外のことがおこり、テストが下記のようにフェイルしてしまう。
1) V1::UsersController POST create should create a user with valid params Failure/Error: expect(response.body['email']).to eq("example@example.com") expected: "example@example.com" got: "email" (compared using ==) # ./spec/controllers/users_controller_spec.rb:16:in `block (3 levels) in <top (required)>'
これはつまり何かというと、response.body['email']
の結果がemail
になっているのだ。
試しにputs response.body
でresponse.body
の内容をアウトプットしてみた。そしたら下記の結果が得られた。
{"id":841425152,"email":"example@example.com","created_at":"2018-12-30T19:26:45.289Z","updated_at":"2018-12-30T19:26:45.289Z"}
これって当たり前だけど、JavaScriptのキーと値のペア式になっているのだ。でも、これこそが問題の原因。なぜなら、Rubyでのキーと値のペア式はJavaScriptのそれとは違うからだ。皆さんもご存知かと思うが、下記のようなシンタックスがRubyのやり方。
{"id"=>841425155, "email"=>"example@example.com", "created_at"=>"2018-12-30T23:07:17.457Z", "updated_at"=>"2018-12-30T23:07:17.457Z"}
そう、=>
のような矢印でシンボルを表現するやり方だ。では、次にどうやったらRubyのわかる形に変更できるかについて見ていこう!!
うまくいく例
JSON.parsse()
これは単純にJSONオブジェクトをRubyのわかるものに変えるだけなのだ。言うなら、to_json()
関数の逆をやっているのだ。
よって、先ほど、puts response.body
でJavaScriptの形になっていたものはputs JSON.parse(response.body)
と改めることで下記のようになる。
{"id"=>841425155, "email"=>"example@example.com", "created_at"=>"2018-12-30T23:07:17.457Z", "updated_at"=>"2018-12-30T23:07:17.457Z"}
つまり、うまくいくRspecのコードは下記のようになる。
describe "POST create" do it "should create a user with valid params" do post :create, params: {user: {email: "example@example.com", password: "foobar", password_confirmation: "foobar"}} expect(response).to have_http_status(:created) expect(JSON.parse(response.body)['email']).to eq("example@example.com") end end
まとめ
このように問題を発見することができれば、あとはしっかりとしたRubyの知識があればこのような問題は解決できる。なので、何かエラーに面したときはいろいろとプリントアウトしてみて、手掛かりを探しましょう!!
皆さんのテストコードがより素晴らしいものになることを祈ります。
ご精読ありがとうございました。では、また次回まで✌
Herokuのステージングブランチとは?(実践編)
こんにちは、皆さん!
ここではどうやってHerokuでステージングブランチを作れるのか、そして、そこで役に立つちょっとした予備知識と一緒にお伝えしようと思う。Herokuのステージングブランチについての解説はこちらの導入編を参照してください。→
Herokuのステージングブランチとは? (導入編) - Programming_Shopの日記
- トピック:
ステージングブランチの作り方
まず、Herokuアカウントを開いて、そして、ステージングブランチにしたいアプリを選びます。ここでは、僕自身のHerokuで例を挙げていく。下記のようにHerokuのアプリケーションがいくつかある。ここで
this-will-be-staging
をステージングブランチにするとしよう。なので、まずそのアプリケーションの詳細に入る。その後、ダッシュボードから
Deploy
をクリック。そしたら、パイプラインを作成するので、
Choose a pipeline
からCreate new pipeline
を選択。***注意***
ここで、本家の方に選ぶHerokuのアプリ内のコードはステージングブランチに選んだコードに変更されるので、くれぐれも失いたくないコードの入ったHerokuアプリを本家として選ばないでください!!
このパイプラインというのはつまりは2つのHerokuのアプリケーションをつなげるようなものである。そしたら、いつでもステージングブランチのコードを本家の方にプッシュすることができるのだ。
名前を付けてパイプラインの作成は完了。ここでは、
heroku-staging-test
という名前にした。そしたら、おそらくこんな感じの画面になったでしょう。まだステージングブランチだけで本家がないので、ここで追加していく。Add app
をクリック。
ここで、今回は最初にホームページで見せたthis-will-be-production
が本家なのでサーチバーからタイプして選択した。そしたら、下記のようにパイプラインが完成。
次はステージングブランチのコードを本家にプッシュして本家のウェブサイトのコードを更新していく。
プロダクションのコードを更新する
ここで、
Promote
というボタンをおして、プッシュを完了すると、下記のような画面になる。これはただいまステージングブランチと本家のコードはまったく同じであるということを言っているのだ。そして、以降ステージングブランチのコードを変えるたびにこのボタンが先ほどのボタンのようになり、またプッシュすることができるようになる。
こうしてパイプラインのセットアップが完了した後にホームページに戻ると、下記のように先ほどの2つのアプリが1つにまとまっているでしょう。
ステージングブランチにプッシュ先を変更する
これについて話す前に、まず注意したいのはステージングブランチはステージングブランチという特別な名前を与えられているが、結局は1つのHerokuのアプリケーションであることを肝に銘じてもらいたい。なので、いつもHerokuにプッシュするようにステージングブランチに更新したコードをプッシュすることができるのだ。
ここで、今エディターで編集しているコードのプッシュしている先がステージングブランチになっていない場合は下記のようにプッシュ先を設定しましょう。
まず、Herokuのページからまずステージングブランチのアドレスをコピーします。ステージングブランチのアプリを開いて、
Settings
をクリック。ちょっとスクロールしたところに下記のようなものがあるので、この赤丸のところをコピー。その後、編集しているコードのディレクトリーをターミナルで開いて、下記のようにHerokuへのプッシュ先を設定する。
(heroku addressの部分に先ほどのコピーしたアドレス。<>は不要)
git remote add heroku <heroku address>
こうすれば、今後Herokuにプッシュする際にはステージングブランチの方にコードが行くようになる。
ステージングブランチの注意点
- ステージングブランチと本家ではデータベースが別々である
ここでもう一度おさらいするが、ステージングブランチもまた1つのHerokuアプリであるので、それ自身にデータベースも存在し、これは本家の方と別のものである。なので、ステージングブランチで新たに足したデータは本家には反映されないし、逆に本家で追加したデータもまたステージングブランチには反映されない。
しかし、これがまたステージングブランチのいいところで、ステージングブランチで様々なデータをテストする際にそれが本家に影響を与えるかどうか気にしなくていいということである。
- 必要なアドオンを再追加する
これまたアプリが分かれているためだが、本家で使われているHerokuのアドオンでテスト時に必要になるアドオンはステージングブランチにもしっかり追加しよう。例えば、メール送信をテストしたいのなら、sendGrid
を追加する。
- 必要な環境変数を再追加する
こちらもまた本家と同じように追加しないと、アプリがうまく動作しないかもしれないのであるのなら追加しましょう。また、その変数の使い方によるが、テストするために本家とは違うテスト用の変数を設定してもよいでしょう。
Herokuのメンテナンスモード
実は、Herokuにはメンテナンスモードがあり、いつでもユーザーがその状態を変更できる。もしも、メンテナンスモードになっている状態で、そのウェブサイトに行くと、下記のようにウェブサイトのコンテンツを見ることができないようになっているのだ。
これがなぜ役に立つのかというと、ステージングブランチのコードを本家にプッシュする際に、Herokuは一度、アプリを止めるので、ユーザーの邪魔をしてしまうのだ。特にアクセスが集中している本家のサイトだと多くのユーザーに影響を与えやすい。なので、一度本家をメンテナンスモードにして、ユーザーのアクセスを無効にして、変にユーザーのデータ更新を邪魔しないようにするのだ。
これもまた簡単で、本家の方のアプリの
Settings
に行って、下記の画面までスクロール。このボタンでメンテナンスモードをオンにしたり、オフにできる。また、もし、本家の方のアドレスをいれたディレクトリーがあるのなら、下記のようにターミナルからでも設定できる。1つ目でメンテナンスモードにし、2つ目でメンテナンスモード解除。
heroku maintenance:on heroku maintenance:off
1つだけ注意したいのは、ステージングブランチをメンテナンスモードにしても意味ないので、先ほどアドレスを設定したステージングブランチではなく、本家でこのコマンドを使うことを覚えておこう。
おまけ
まとめ
ご精読ありがとうございました。では、また次回まで✌
Herokuのステージングブランチとは?(導入編)
こんにちは、皆さん!
ステージングブランチというものをみなさんもどこかで一度は聞いたことがあるかもしれない。特にすでに会社でHerokuを使っているという場合はなおさらである。今回はWeb開発を効率化し、そして、メインテナンスをより簡単にさせてくれるステージングブランチについて紹介していきます。(実践編はこちら→
Herokuのステージングブランチとは?(実践編) - Programming_Shopの日記
- トピック:
- リソース:
ステージングブランチとは?
以下の内容を理解するにはGitの知識が少し必要になってきます!
まず、初めにステージングブランチとは何かについて説明していこうと思う。ざっくり簡単に言うと、GitのマスターブランチがHerokuにデプロイしたコードでステージングブランチはGitのマスターブランチ以外のブランチといえる。つまり、実際に運営しているウェブサイトとは別にもう一つ同じ内容のウェブサイトを持つことができるということだ。
もっと一般的な例でいうのなら、劇を例に挙げて、ローカルでのテストが練習、ステージングブランチでのテストがリハーサル、そして、本家のウェブサイトにデプロイが本番といったような感じだ。(以下の図参照)そして、Gitでマージするように、このステージングブランチのコードはいつでも本家の方のウェブサイトにプッシュすることができるのだ。
ステージングブランチの利点
大きく分けてステージングブランチを使うことには2つの利点があります。
- Herokuにデプロイした際、エラーがあっても、ユーザーに影響を与えない
Herokuとローカルでテストしたときに内容が違うことはよくある。例えば、レイアウトのサイズ感が少し違う(これに関してはどうしてなっちゃのかいまだに謎)など。これをユーザーが直接見る本家のウェブサイトにデプロイしないで、ステージングブランチにデプロイすることで、事前確認ができ、修正することができる。
- Herokuでしかテストできない要素がある
少し1個目とも被るが、例えば、メールをユーザーに送信するものなどは確かにローカルでテストコードを書いてテストしてみることもできるが、やはり、最終的にはHerokuにデプロイした後の状態で確認する必要がある。この時、本家に直接デプロイすると、ユーザーもその新しいエラーのあるかもしれない機能に触れる可能性があり、非常に望ましくない。なので、まずはステージングで確認するところから始める。
これらを踏まえると、下記のような仕事の流れができる。このようにプログラマーはローカルとステージングの間を行き来し、最終的に完全なものだけをユーザーに届けるのというシステムになっているのだ。
まとめ
Herokuのステージングブランチとは?(実践編) - Programming_Shopの日記
ご精読ありがとうございました。では、また次回まで✌
Ruby on Rails開発のインターン (Day 36 最終日)
こんにちは、皆さん!
ついにインターン最後の日がやってきた!時間がたつのって本当に早い。インターン初日がまるで昨日のことのように感じられる。振り返ってみると、弁当たくさん作ったな(笑)
まあ、結果的にプログラミングに関して様々な知識を身につけられた気がする。すごくためになるいい経験だった。
最後の日に関してだが、おそらく新しくこれとしたことを始めることはないだろうが、ここまで僕が書いてきたコードの整理などをしてちゃんと他の人に引き継いでもらえるようにすることが主となるかな。最後の日も楽しんでいこう!
- トピック:
- 疑問:
- 問題:
- 学習した内容:
- Railsでルートを効率よく定義する方法
- 今後やってみたいこと:
- リソース:
ネステッドルートを使い、Railsにおけるルートを効率よく定義する
今回はRailsガイドでその基礎を学んだ。(Rails のルーティング | Rails ガイド)
この機能は難しくないし、僕も結構好き。もう本当にコードがきれいになる。
例えば、ネステッド状態のコントローラー、post/:id/image/:id
(簡単に言うと、たくさんの写真を持ったたくさんの投稿を持つウェブサイトであり、このように指定することでその中の一つの投稿の一つの写真を出してくれる)。このURLを書くときにshow
アクションのためだけにこう下記のように書きたくなるかもしれない。
get 'post/:id/image/:id', to: 'images#show'
しかし、これをさらにほかのアクションに対してもやらなくていけなく、それはまた大変な量のコードなのであり、間違いも発生しやすい。
だが、下記のようにネステッドの機能を使うことでこれがすごく簡単になるのだ。
resources :posts do resources :images end
これだけで基礎的なRESTfulのアクションすべてを作り出したことになる。
もちろんいくつかのアクションに制限をかけたいときも簡単。例えば、投稿のedit
アクションだけをなくしたいのなら
resources :posts, except: [:edit] do resources :images end
ネステッドルートの更にいいところはcollection
フレームが使えることだ。これがあるだけでRESTfulに該当しない基本的でないアクションも簡単に定義することができるのだ。例えば、hello
アクションをpost controller
に追加したいとする。そしたら、posts/hello
でそのURLを構築したいのなら、普通、下記のようにすればできる。
get 'posts/hello', to: 'posts#hello'
しかし、collection
があればこのように書き換えられる。
resources :posts do collection do get 'hello' end end
これはより簡単だし、何より見やすい。あとでここに何か追加したいときはそのままこの枠の中に足すだけで前半部分のposts/
をもう入れなくて済む。また、posts/
部分が変わる場合も一か所だけ変えればすべてが一緒に変わるという。
まとめ
最後の一日ということで、新しいことを始めることもできなかったが、存在するバグをいくつかすぐに直すことができたのでいいとしよう。最後にこの小さなコミュニティーに貢献できてよかった。
最後にマネージャーと少しこれからの僕のプランについて話し合った。彼は僕が来学期を終えた後、どんなことをするのか結構興味津々であった。今のところ、僕の考えでは、Airbnb, Twitter, Google, Microsoftのような大きなIT会社で働いてみたいなとは思っている(僕なんかを採用してくれるのならの話だが(笑))。明るい自分の将来を願いつつ、2か月間本当にお世話になりました。
ご精読ありがとうございました。では、また次回まで✌