【Rails】RSpecでjsonファイルを読み込んで保存するテストを書く
きっかけ
今回はjsonファイルを読み込んで、そのjsonデータを保存する実装をしていました。
RSpecも書くということでしたが(当たり前やん!)、jsonデータを読み込む時のやり方に少し躓いたので、まとめてみようと思います。
実装内容
という感じ。
RSpecを書くときは、外部ファイルサービスへのアクセスはしないでモックと/spec/fixtureに置いたファイルで対応する。
そもそもRSpec初心者の私には、 外部ファイルサービスにアクセスしないでテストする
というのをどうしたらいいのかから悩む事になった。
モックを使うことを知る
こちらの記事を参考に直接外部ファイルサービスにアクセスしない方法が見えてきました。
ここで私が使ったのは、1番よく使われるらしい double
メソッドと allow
メソッド。
jsonを読みにいく処理が走るときは、/spec/fixtureに置いたjsonファイルの中身を返すというように書きました。
例えば、こんな前提
- userに対するscoreが保存されているjsonデータが外部ファイルサービスのバケットにある
- バケットにコールするモジュールが
CallBucket
- データを保存する処理は
StoreJsonData
にかかれている CallBucket
はStoreJsonData
の中から呼ばれる- テストは
StoreJsonData
で保存されたsocreが正しいかを確認する sample.json
にはとあるuserのscore=3
というデータがあるとする
これをテスト書いてみる
let(:json_file) { Rack::Test::UploadedFile.new("#{Rails.root}#{file_path}", "application/json") } before(:each) do bucket = double('bucket') json_data = JSON.parse(File.read(json_file.path)) allow(CallBucket).to receive(:new).and_return(json_data) StoreJsonData.new.import(bucket) end context "sample data" do let(:file_path) { "/spec/fixtures/sample.json" } it "save" do expect(user.score).to eq 3 end end
詰まったところ
JSON.parse(data)
としていますが、最初は JSON.load(file)
としていて、rubocopにセキュリティ的によくないよ!と怒られました。
ただ、単純にJSON.parse(file)
ではだめで、一回オブジェクト化した状態で JSON.parse
を使わなければならないことに少し時間がかかりました。
before/afterはこんな感じ
before
json_data = JSON.load(json_file.path)
after
json_data = JSON.parse(File.read(json_file.path))
JSON.parse
にはファイルの中身をロードする処理はないので、事前にfile.readしてjson文字列として渡してあげないといけないということらしいです。
さいごに
まだまだRSpecは勉強中ですが、次からファイルの読み込みが必要なRSpecはすぐに書けそうです!
でも全体的にRSpecの知識が足りてないから、一回体系的にやりたいところ。。
時間を見つけてコツコツとキャッチアップできればと思います。
【AWS】EC2×dockerでRails開発環境を構築する②
前回の続きです。
前回まではEC2の立ち上げでしたが、AWSのこのサービスを使うともっと簡単にできそうなことに気が付きました。。
まだ試してないけど、やって見る価値あるかも。。
ちなみにAWS cloud9は1~2分ですべての設定をしてくれたのでとても感動的だったのですが、
静的なIPを設定できなかったので、sshが面倒で諦めました..
VScodeでsshする
この動画を参考にしました。拡張機能は Remote - SSH
にしましたが、設定内容や操作は同じようにできました。
このdocker講座シリーズ、とてもわかりやすかったので、dockerに自信ない人はおすすめ
EC2にdockerをインストール
このドキュメントのインストール部分だけやりました。
docker-composeもインストール
このあと起動するdocker-compoeのversionにあったものをインストールするようにする。
gitをインストールしてssh接続しておく
gitとgithubは最近httpsで接続することを推奨しているけど、EC2の場合は専用のIAM作ったりしないといけないので、sshで接続することに。
yarnをインストールしておく
なんだかんだ以下のコマンドで直接ダウンロードしたらエラーにならなくなった。
curl -o- -L https://yarnpkg.com/install.sh | bash #パッケージをダウンロード&インストールされる source ~/.bashrc yarn -v #インストールできたか確認
docker-compose buildする
先方のアプリケーションを手順に従ってbuild
localhostを使わないでホストを変更する場合
開発環境だけどlocalhostではなく、特定のドメインホストを使うようにするところで詰まりました。
EC2内の/etc/hostsをこのようにする。
$ sudo vi /etc/hosts 127.0.0.1 xxxx.zz 127.0.0.1 yyyyyy.zz
その後、自分のPCの/etc/hostsにも以下のように設定する設定する。
この時、EC2の立ち上げの際に設定したElasticIPにして設定する。
ElasticIPが52.69.70.22
だとしたらこんな感じ。
$ sudo vi /etc/hosts 52.69.70.22 xxxx.zz 52.69.70.22 yyyyyy.zz
注意点
従量課金なので業務終了時に止めないといけません。
また、swapもつけたほうが安心かもです。
【AWS】EC2×DockerのRails開発環境を立てる①
きっかけ
今回開発に携わることになったアプリケーションが今まで以上にスペックが必要ということでしたが、今持ってるMacBook Airはそこそこ新しく気に入ってるので買い替えたくない状況。。
でも実際に環境を立ててみると、CPUが足りなくてギリギリ動くけど、すごくヌルヌル。。
1クリックに1分ずつぐらいかかるので、生産的にやばすぎ…
ということで、前からやってみたかったクラウド環境での開発をやってみることにしました〜!
事前に用意するもの
手順
EC2を立ち上げる
- AWSコンソールにログインし、EC2を起動します。
- インスタンスの選択 私はメモリが最低16GBは必要だったので、とりあえずt2.xlargeを選択しました!
- インスタンスの詳細設定 パブリックIPを有効にします。それ以外はデフォルトで。
- ボリュームの設定
dockerを使う時は10GBぐらいあった方がいいと書いてあったので、20GBにしておきました。
- タグを付ける
なんのインスタンスかわかりやすいようにNameタグだけつけておきます。
後で変更もできるし、なくても次に進めます。
- セキュリティグループを設定する
私はとりあえずsshだけ開けて、必要な時に開けていったので、ここはsshだけです。
結果的には以下のような感じになりました。
- ssh / ポート:22 / [作業場所IP]/32 ←初回で設定したもの
- カスタムTCP / ポート:3000 / [作業場所IP]/32 ←Railsアプリケーションを立ち上げるポート
カスタムTCP / ポート:1080 / [作業場所IP]/32 ←その他アクセスが必要なポート
設定完了
このあと確認ページが出てくるので、内容を確認して、インスタンスを開始します。
数分で立ち上がるはずです。
ElasticIPをEC2に割り当てる
先程、自動的にパブリックIPを割り当てるようにしましたが、インスタンスを再起動するたびにIPアドレスが変わります。
IPアドレスが変わってしまうと後ほど出てくるVScodeからのアクセス時に毎回IPアドレスを変更しないといけないので、少し面倒です。
なので、Elastic IPを使ってIPを固定しておくと便利。
ただし、少しお金がかかりますので、節約したい人はがんばって毎回修正しましょう。
設定方法は以下の記事を参考にさせてもらいました。
②につづく...
【Rails】ActiveStrageを使ってみた話
きっかけ
Rails5.2からの機能だから使ったことがありませんでしたが、新規実装時にファイル添付機能をこれで実装することになりました。
その時にキャッチアップした内容を書きたいと思います。
ActiveStrageの設定
1. 専用テーブルの作成
すでにされているいる場合はスキップします。
まだ無い場合は rails g XXX
を使って先に受け皿を作っておきます。
2. 環境への設定
開発はローカルに、productionはS3にするというような切り分けができる
私はproductionの設定がどうなるかわからなかったので、とりあえずベースだけ作ることにした
※とりあえず、regionは東京(ap-northeast-1
)にしておく
本番保存先が決まったら、以下のことをするらしい
Active Storageのコア機能では、s3:ListBucket、s3:PutObject、s3:GetObject、s3:DeleteObjectという4つのパーミッションが必要です。ACLの設定といったアップロードオプションを追加で設定した場合は、この他にもパーミッションが必要になることがあります。
- 環境変数をAWSから直接持ってきたい場合はAWS SDKを使う→AWS SDK for Ruby の設定
他に検討したことはこれ。
- ミラーサービスは一旦つけない
- gemはs3に連携する環境だけで良い気がするが、一旦localの場合も入れておく
3. レコードとS3データの紐付けをして保存できるようにする
- レコードの紐付けは
has_many_attached :evidence_files
という設定を作ったモデルに書く
4. viewに添付ボタンを作る
私は、file_fieldを使用しました。
multiple: true
をつけると複数選択可能になります。
最後に
主にRailsガイドを見てやったやりましたが、わかりやすく書いてあってよかったです。
全体の流れはこのブログを参考にさせてもらいました
【Rails】migrationしたりし直したりするときのコマンドまとめ
きっかけ
新しいサービスの開発をお手伝いしている時、仕様がどんどん変わり、DBの構成の変化も大きかったです。
その時テーブルのカラムの構成を変えたりすると、今あるデータをまるっと入れ替えたいことがありました。
Railsにはサクッと直してくれるコマンドがたくさんあるので、整理しておこうという感じです。
コマンド集
- テーブルを作る
rails db:migrate
- テーブルは消さずにデータだけ消す
rails db:reset
- テーブルも削除して、全てのテーブルをmigrateし直す
rails db:migrate:reset
seed.rbにある初期設定のデータセットを一括で入れる
rails db:seed
- ひとつ前のmigrationをなかったことにする
- ※migrateする時と同じmigrationファイルの状態じゃないとできない
rails db:rollback
→これを使う時は、
rails db:rollback
- migrationファイルを修正
rails db:migrate
する
の順にやらないとエラーになる
rollbackが使えない時
よく使うデータや重要な検証ケースのデータをseedに書く
rails db:migrate:reset
をするrails db:migrate
をする- seedを流す
※rails db:migrate:resetはMySQLでいうdrop tableなので、以前のmigrationファイルがどうなっているかは関係なく実行できる
※seedに書かれたデータ以外はすべてなくなるので注意
最後に
今日は簡単によく使うDB関連のコマンドをメモ的にまとめました。
自分のアプリケーションもいつか作ってみたいので、その時に活用できそうかな。
【Rails】Mailhogを使ってみる@MacOSのローカル
Mailhogを使ってみたい!
会社で使ったことはありますが、他の方が設定してくれたのをDockerでまるっと使っていました。
今回、自分で初めて設定してみて、若干つまったのでキロクしておこうと思います。
Mailhogって何?
goで作られたオープンソースのメールシステム。
githubのスターも9000件以上と最近ちょっと人気らしい。
使うメリットは、個人的にはこの辺に感じてる
今回やりたいこと
今開発しているシステムはまだ駆け出しで、docker化とかもされてません。
そのため、簡単にローカルでテストしたいと思いました。
で、調べてみると、phpやdockerで使う方法はよく出てくるのですが、Railsでやる方法があまりなくちょっと困りました。
実際どうやった?
以下のような手順で進めました
1. Mailerを実装する
こちらの公式ガイドを参考にまずはMailerを用意し、メールの本文まで準備しました
2. Mailhogをインストール
GitHubのReadmeにかかれている通りにインストールします。
私はMacOSだったので、以下を実行しました。
brew update && brew install mailhog
3. sendmailの代わりのmhsendmailをインストール
readmeを見るとmhsendmailを使うというのでインストールします。
brew install go go get github.com/mailhog/mhsendmail
4. RailsからMailhogに送付するようにする
最後にconfig/environments/development.rbに以下のような記述を追記します。
config.action_mailer.delivery_method = :smtp config.action_mailer.smtp_settings = { location: '/usr/local/bin/mhsendmail', port: 1025 }
これでRailsのサーバーを立て直して、送付してみたらできました!
実際にはこんな感じ!
まとめ
今回はMailerActionのsendmail_settingsのオプションを学びました!
こういった設定系はやらないと覚えないので、いい経験でした。
【Rails】トランザクションについて見直してみる
きっかけ
- 働いていた時、特にコード規約がなく、いろんな人が触ったコードだったためか、いろんな書き方がされていた
- 複数のレコードを同時にsaveする時に、使うのは知っている
- ただベストプラクティスはどうなのかをちゃんと考えたことなかったので見てみる
学んだこと
そもそもエラーハンドリングの心得から勉強してみる
- こちらの記事がとても勉強になった
- Ruby on Railsを使って、大事なところを簡潔に書いてくれていてありがたい
- アンチパターンと、その場合どうすべきかが書かれている
- 運用のことを考えると、以下の2つの内容はすごく重要だったな。。
特別な理由がない限り、エラー情報を破棄してはいけない。 最悪の場合、エラーの原因を特定できなくなる。
エラー処理も必ずテストすること。 「たぶん動くはず」でそのままコードをリリースしてしまうと、最悪の場合「エラー処理のバグによるエラー」が発生してしまい、元のエラー内容が失われてしまう場合がある。(二重障害) こうなるとエラーの原因を調査するのが非常に難しくなる。
Railsのトランザクションはどう使うのか?
- 上記の記事の最後の項目が今回の内容に近い
- 基本的な書き方はRailsガイドを確認
- これらをみるとわかるように、
.transaction
をつけた場合は、.save
を通った瞬間DBにcommitされるわけではなく、ブロックを抜けた瞬間にDBにコミットされる- つまりコミットタイミングをコントロールしている
. lock
や.with_lock
を使うことで、同じレコードを書き込まないようにすることもできる- この時はdeadlockが発生しないような処理にする
ふと思い出した他の書き方
- 昔やってた時に、モデルに対して
.transaction
をかけただけでなく、以下のような書き方もしてたな〜と
ActiveRecord::Base.transaction do # データを作るような処理とsave end
- 要は同じ処理で得られる結果は同じ
ActiveRecord::Base
は各モデルの親クラスであるため- Modelで
ActiveRecord
を継承しているものが対象
応用編
- その他、いろんなパターンのトランザクションの使い方は、この記事がわかりやすかった
- 中でもなるほど〜って思ったのが、「複数のデータベースコネクションに分散されない」ということ
- 複数DBを取り扱ったことがなかったので知らなかった
- 複数DBを跨いでトランザクションをかける時には、
.transaction
をネストにしないといけないそう
おまけ
- ついでにコールバックも読んでみた
- コールバックも密接に関わってくるので、また今度まとめたい