volpe’s diary

フリーランスじゃなくなったプログラマ volpe が日々便利だなぁと感じたことを中心に綴るブログです

Rails で webmock と vcr の環境を作るメモ

Rails で外部WebサービスAPI を叩く spec を書く際に、HTTP通信を mock にしたくなったので webmock と vcr を使ってみた。

これらを使うと初回だけリアルな通信をして通信内容をファイルに保持してくれるので、2回目以降はリアルな通信なしに spec を動かすことが出来る。 保持したデータは git に登録しておけば他のメンバがテストを動かしてもリアルな通信が発生しない。これは便利!

ググればどこにでも書いてるような内容だけど、自分用に導入手順をメモしておく。

前提

  • rspec を使っている

導入手順

  • Gemfile の testwebmockvcr を追加して bundle install
  • spec/rails_helper.rbrequire 'webmock/rspec' を追加
  • spec/support/vcr.rb を追加して以下を記述
VCR.configure do |c|
  c.cassette_library_dir = 'spec/cassettes'
  c.hook_into :webmock
  c.configure_rspec_metadata!
  c.ignore_localhost = true
end
  • spec ファイルの scenario または describe に vcr の記述を追加。 (:hoge_fuga は任意の文字列)
scenario 'hoge の fuga を確認する', vcr: { cassette_name: :hoge_fuga } do

実行

  • 普通に rspec を実行すると1回目に spec/cassettes/hoge_fuga.yml が作成され、実際の通信のデータが記録される。 (初回はリアルな通信が走るので注意)
  • 2回目以降は上記ファイルのレスポンスを返すようになる
  • spec 毎に cassette_name を変えておけばそれぞれの通信内容を保持できる。
  • 必要なら生成された yml を直接編集して挙動を変えることも出来る。

トラブルシューティング

既存の Rails プロジェクトに webmockvcr を導入すると、すでに HTTPリクエストを行なっている spec で以下のように軒並みエラーになってしまう。

     VCR::Errors::UnhandledHTTPRequestError:

       ================================================================================
       An HTTP request has been made that VCR does not know how to handle:
         POST https://slack.com/api/auth.revoke

       There is currently no cassette in use. There are a few ways
       you can configure VCR to handle this request:

         * If you're surprised VCR is raising this error
           and want insight about how VCR attempted to handle the request,
           you can use the debug_logger configuration option to log more details [1].
         * If you want VCR to record this request and play it back during future test
           runs, you should wrap your test (or this portion of your test) in a
           `VCR.use_cassette` block [2].
         * If you only want VCR to handle requests made while a cassette is in use,
           configure `allow_http_connections_when_no_cassette = true`. VCR will
           ignore this request since it is made when there is no cassette [3].
         * If you want VCR to ignore this request (and others like it), you can
           set an `ignore_request` callback [4].

       [1] https://www.relishapp.com/vcr/vcr/v/5-0-0/docs/configuration/debug-logging
       [2] https://www.relishapp.com/vcr/vcr/v/5-0-0/docs/getting-started
       [3] https://www.relishapp.com/vcr/vcr/v/5-0-0/docs/configuration/allow-http-connections-when-no-cassette
       [4] https://www.relishapp.com/vcr/vcr/v/5-0-0/docs/configuration/ignore-request
       ================================================================================

いくつか対策は提示されているけど、既存はそのまま HTTPアクセスしちゃっていい場合は spec/support/vcr.rballow_http_connections_when_no_cassette = true を追加してあげる。

VCR.configure do |c|
  c.allow_http_connections_when_no_cassette = true   #++
  c.cassette_library_dir = 'spec/cassettes'
  c.hook_into :webmock
  c.configure_rspec_metadata!
  c.ignore_localhost = true
end

もしくは mock 化しちゃいたい場合は、vcr: { cassette_name: :xxxxxxxxxx } を付加してあげればいい。

参考

github.com

github.com

あたらしいこと

新しい技術に触れることはとても楽しい。僕がプログラマだからなのかな。他の職業でもそうなのかな。

日々仕事や趣味で作るプログラムは自分の知っている範囲の知識で「こなしている」ことが多い。特に既にある程度完成されたプロダクトが手元にある時は、機能を追加したり内部処理を改善したりする方がハードルが低くて楽だし成果が目に見えやすい。でも、最初はいいけれど長い時間が経ってくるとだんだん物足りなくなってくる。プロダクトは洗練されていくけど自分自身の成長をあまり感じられなくなってくる。

そんな時は、思い切って巷で噂になっている新しい技術を触ってみることにしている。イチからチュートリアルの通りコードを書き始めることもあるし、手元のプロダクトの一部を書き換えて新しい技術を適用してみたりする。最終的にそれがモノになるかどうかはわからないけれど、今まで知らなかった別の概念や考え方を知る機会になる。それはきっとプログラマとしての成長に繋がるんじゃないかと思う。

僕は飽きっぽいので、新しいものを触り始めても他の事に興味が移ってどっちつかずの状態にもなってしまうことが多い。でも、それはそれで良いと思ってる。「ちょっとかじったことがある」という経験はその後のプログラマ人生の中で決して無駄にならないと思うし、一度始めてしまっていれば、またやりたいと思った時に再開するのもそれほど億劫ではないし。

1つのことを続けることも大事だけど、どちらかと言えば「これ面白そうだから触ってみたいな」という気持ちを大事にしたい。その気持を何かの制約でぐっと抑えてしまうのがすごくもったいない。それを試せる状況にあるのなら、可能な限りまずはやってみてからその気持を確かめたい。「こんなもんか」でもいいし「これは面白い!」でもいいし、やってみたら何かが見える。やってみないと、何も見えてこない。

そんなことを思いながら、今日も、ふと触りたくなった技術を触ってみている。

2015/11/05 01:19


数年前に note に書いた記事をふと思い出したのでこちらにも転記してみた。この後、彼は何を触ったのか気になる。

今はこの頃とは状況が変わって、仕事で使う技術が自分にとってあたらしいものばかりだから仕事を通して得られる技術的な刺激がとても大きくなっている。 そしてあたらしいものを知れば知るほど、読みたい本や手を動かして試したいことがどんどん増えていく。。

ただ、家庭の事情で自分1人の時間が激減している状況の中で、この限られた時間を何に当てるべきかというのも悩みの1つでもある。 やりたい事とを不意に空いた時間とかにあまり迷わずに効率よく取り組めるような仕組みを作りたいなぁ。

まぁ、悩んでいても時間はどんどん過ぎてしまうので、とりあえず今夜は最近気になってる Go言語のツアーを少しやってから寝よう。

go-tour-jp.appspot.com

Mac 上の Bluetooth ヘッドフォンでテレビ会議を aptX で聴く方法

概要

MacBookProにマイク付きの Bluetoothヘッドフォンを接続した際のデフォルトのコーデック(SCO)ではテレビ会議の音質があまり良くなかったので、マイクを外部機器に変更し、アウトプットのコーデックを aptXで接続するようにした。

これでテレビ会議の音声はもちろん、音楽も高音質で聴けるようになった。

やり方としてはマイクの設定を Bluetooth機器のではなく、別の機器(本体マイクや外部マイク)に変更するだけで、アウトプットのコーデックは AAC に切り替わるが、さらに高音質の aptX にするのと、毎回接続の度に自動的に同じ設定を復元してくれるようにした。

上記を実現するにはいくつかのサイトの情報を拾いつつ専用ツールのインストールと多少の設定が必要で、まとまった情報がなかったので忘れないうちに手順をメモしておく。

また、本設定を適用した WH-1000XM3 の使用感は WH-1000XM3 でいつでもどこでも精神と時の部屋に を参照。

前提機器

  • MacBookPro 13inch (2017モデル)
  • ヘッドフォン: WH-1000XM3
  • マイク: iPhone純正イヤフォンのマイク
  • テレビ会議ソフト: zoom

設定手順

  • WH-1000XM3 と iPhone純正イヤホンを Mac に接続する
    • WH-1000XM3 は Bluetooth で接続
    • iPhone純正イヤホンは有線でイヤホンジャックに接続
  • aptX を有効にする
  • 機器セットで外部マイクを設定する
    • 参考: https://support.apple.com/ja-jp/HT202000
    • Finder で、「移動」>「ユーティリティ」の順に選択する。Audio MIDI 設定アプリケーションを開く。
    • 左下の「+」ボタンから機器セットを追加する。
    • WH-1000XM3 の出力と内蔵マイクを選択する
    • f:id:volpe0104:20190509094553p:plain
  • 「システム環境設定」の「サウンド」で出力と入力を設定する
    • 出力には「WH-1000XM3」を設定
    • 入力には先ほど追加した「機器セット」を設定
    • これで WH-1000XM3 の電源を入れた際に自動的にマイクが iPhone純正のイヤホンに切り替わる
    • f:id:volpe0104:20190509094548p:plain
    • f:id:volpe0104:20190509094545p:plain

確認方法

  • 以上で設定は完了。正しく aptX になっているかは以下で確認できる
    • option を押しながらツールバー上の Bluetoothアイコンから対象機器を選択するとコーデックが表示される
    • f:id:volpe0104:20190509094542p:plain
  • zoom のオーディオ設定でも設定が反映されている
    • f:id:volpe0104:20190509094538p:plain

正直、AACとaptX の違いはハッキリは分からなかったけど、SCOとは全く比べ物にならないくらい音質が良くなるのでわかるはず。

WH-1000XM3 でいつでもどこでも精神と時の部屋に

SONYノイズキャンセリングヘッドフォン「WH-1000XM3」を買ってみたら最高だった。

f:id:volpe0104:20190105230529j:plain
WH-1000XM3

購入の経緯

2018年の年末あたりに、ビデオ会議用にワイヤレスのイヤホンかヘッドフォンで良いのがないなー、ってなんとなく探していた時に、たまたま実家に帰ったら父親から Boseノイズキャンセリングヘッドフォンを購入したと自慢されたので、俄然ノイキャンヘッドフォンに興味を持ってしまった。

調べてみると現状のハイエンドノイキャンヘッドフォン市場は Bose の 「QuietComfort 35 wireless headphones II」と SONY の 「WH-1000XM3」 の2択らしい。安い買い物ではないので2週間ほど吐くほど悩んだ挙句、ノイキャン性能が上回っているという 「WH-1000XM3」 の方を購入してみた。

半年弱使ってみて今のところとても気に入っているので自分視点での使い心地などを書いておこうと思う。詳細なスペックなどには触れないので、公式HPなどを見るといいと思う。

f:id:volpe0104:20190113221112j:plain
BOSESONY

用途

主な用途は以下の通り。最初はビデオ会議で使ってみてダメそうなら、最悪月一の出張時の飛行機で使えればいいかなという感じだった。結局だいぶ使い勝手が良かったので外に出るときはだいたい持ち運ぶようになってる。

  • リモートワークでのテレビ会議
  • 仕事中に音楽を楽しむ
  • 仕事中に無音で集中する
  • 移動中のプログラミングのお供に
  • 散歩のお供に

リモートワークでのビデオ会議で

メインの使い方になるであろうビデオ会議だったけど、正直最初は期待外れだった。 というのも、MacBookPro に Bluetooth で普通に接続してマイクを WH-1000XM3 を使うようにすると、コーデックが SCO になってしまい、聞こえてくる音質がとても悪い。ビデオ会議の会話もザラつくし、音楽なんてとても聴けたもんじゃない感じだった。

しかし、色々調べてみると WH-1000XM3 のマイクを使わなければ出力側は高音質の AAC や aptX で接続できることがわかり、現在はマイクに iPhone純正イヤホンのマイクを使いつつ、 WH-1000XM3 のコーデックは aptX にして使用している。そのおかげで音質はとても良くなった。(具体的なやり方はこちら 「Mac 上の Bluetooth ヘッドフォンでテレビ会議を aptX で聴く方法」)

f:id:volpe0104:20190109010225j:plain
iPhone純正マイクを簡易スタンドに設置

iPhone純正イヤホンはたまたま手元にたくさんあるので使っているけど、マイク性能は地味に良いらしい。ただ無指向性で周囲の音(特に子供の泣き声や生活音)も拾ってしまうので、将来的にはもっと性能の良い指向性マイクにしたいところ。(模索中)

ビデオ会議での使用感としては相手の声の遅延はほぼ感じずかなり良く聞こえるし、こちらの声もそこそこの音質で聞こえているらしい。相手方が複数人で会話している場合でも、こちら側のボリュームコントロール次第でかなり細かい会話まで拾うことができる。

難点としては、ノイキャンON状態では自分が発する声がほぼ聞こえないので会話しにくいというのがあったが、ここで WH-1000XM3のウリの1つの外音を取り込む機能「アンビエントサウンドモード」にしてみると、自分の声もはっきり聞こえるようになるのでだいぶ快適に話せるようになった。

そんなわけで周囲がそれほどうるさくない場合は「アンビエントサウンドモード」にして会話することにしている。本製品を買った当初は、ノイキャンなのにわざわざ外のノイズを拾う「アンビエントサウンドモード」なんて使わなさそう、と思っていたけど意外な使い道があった。さすが SONY

仕事中に音楽を楽しむ

リラックスして仕事を行うには心地よいBGMが欠かせないので、僕は作業デスクに設置している amazon echo をステレオに繋いで常にBGMを流しているのだけど、自室で1人作業していても意外と環境ノイズが多いことに気づいた。 例えば、暖房、空調、PCのファンの音、ルンバの音、などなど。 特に夕方に子供達が帰ってくると別室で遊んでいても結構賑やかな声が聞こえてきて集中できないことがある。

そんな時に WH-1000XM3 を装着するとスゥーっと無音の世界に入れるのが気持ちいい。音楽も作業の邪魔にならない程度の僅かな音量で流しておくとより没頭できる。 ただあまり長時間装着しっぱなしにしていると耳周りが蒸れるので適度に外してい耳を休ませている。

仕事中に無音で集中する

本当に仕事に集中したい場合はノイキャンモードで音楽すら流さずに装着することもある。 まさに精神と時の部屋。外界の生活音から遮断された世界はなんと心地の良いものか。

移動中のプログラミングのお供に

WH-1000XM3 のノイキャン性能をフルで発揮できるシチュエーションはやはり飛行機や車など乗り物に乗っている時だろう。 特に出張時の飛行機の中で一度装着するともうコレなしではいられなくなる。飛行機の中にいるにも関わらず、あまりに快適過ぎて隣に人が座っていようと多少揺れようとプログラミングが捗りまくる。

また、不意にCAさんが声を掛けてきた場合でも、サッと外して首にかけられるので臨機応変に対応できるし、機内放送が気になった場合でも右手をヘッドフォンに当てれば一時的に外音を取り込める機能があるのでいちいちヘッドフォンを外す手間が省ける。

応用編としてはまだ勇気が出なくて試してないけど、OculusGO と WH-1000XM3 を装着して Netflilx など見ようものなら、もう飛行機の中にいることさえ忘れてしまいそう。(たぶんもう数年したらもうそれが普通な世界になっていそう)

持ち運びは首に掛けておくか愛用している「ひらくPCバック nano」に収納している。一見大きそうなヘッドフォンだけど折りたたむと驚くほどコンパクトになる。

f:id:volpe0104:20190108000220j:plain
ひらくPC nano にも余裕で入る

散歩のお供に

WH-1000XM3 は歩きながら使ってもノイズが少ないのがいい。これまで外で音楽を聞くときは、完全ワイヤレスイヤホンの Zolo liberty を使っていたけど、耳を完全に塞いでいるせいか歩く度に結構な振動音がして不快だった。WH-1000XM3 だとそれが無い。さらに、ノイキャン機能で例えば東京の賑やかな街を歩いていても、車道や工事の音が驚くほど軽減されて清々しい気分で闊歩できる。

しかも寒い日には耳あてがわりになるので寒さの厳しい北海道ではうってつけ。(ただ氷点下になると誤動作を起こす可能性があるらしい)

ただ言うまでもなく、ノイズが低減される分、混み入ったところでは十分に周りの状況に気を配っていないと身の危険を伴うので注意が必要。

まとめ

初めてのノイキャンヘッドフォンの WH-1000XM3 の個人的な用途をざっと書いてみた。 ほんと「持ち運べる精神と時の部屋」なので集中して作業をしたい場合にはうってつけだと思う。

最後に自分が思うメリットとデメリットを書いておく

メリット

  • 持ち歩ける精神と時の部屋
  • カフェでも、飛行機でもコーディングが捗る
  • OculusGO と組み合わせれば没入感倍増
  • 東京のノイズだらけの街を歩いてても精神が落ち着く
  • 寒い日は耳あてがわりになる(氷点下は注意)
  • 完全ワイヤレスなのにバッテリーの心配がほとんどない (なんと30時間も保つ)
  • TV会議では外付けマイクを使うと aptX の高音質で聴ける

デメリット

  • 夏は多少蒸れそう
  • ビデオ会議で付属マイクを使うと音質が悪い (SCOコーデック)
  • Mac に aptX,AACで繋ぐと付属マイクは使えない
  • マイクを外付けにすると自分の声が聞こえにくい (アンビエントモードにすると割と聞こえるようになる)
  • ノイキャンされ過ぎて野外ではちょっと恐い (特に夜はやめたほうがいい)

既存の Nuxt.js サービスを新規 Firebase プロジェクトにデプロイする手順

Firebase の Hosting に既にデプロイしている Webサービスを新規プロジェクトにデプロイする必要があったので備忘録として手順をメモしておく。 理由としては、本番と開発で環境を分けたくなったため。

初期設定はこちらに記載している。

前提

  • Nuxt.js で作った Webサービスをデプロイする(クライアントのみの機能)
  • dotenv で環境変数を管理している
  • Google認証を使っている
  • Cloud Firestore を使っている
  • Storage を使っている

概要

  • プロジェクトを追加
  • Google認証を有効化
  • Cloud Firestore のデータベースを作成
  • Storage は特にやることなし
  • デプロイ

手順

  • プロジェクトを追加 f:id:volpe0104:20190416005433p:plain

  • プロジェクトの情報を取得 f:id:volpe0104:20190416005427p:plain f:id:volpe0104:20190416005410p:plain

  • .env に記述する f:id:volpe0104:20190416005441p:plain


  • Authentication を選択 f:id:volpe0104:20190416005512p:plain f:id:volpe0104:20190416005506p:plain

  • Googleを有効にする f:id:volpe0104:20190416005520p:plain f:id:volpe0104:20190416005527p:plain


  • Cloud Firestore を選択 f:id:volpe0104:20190416005446p:plain f:id:volpe0104:20190416005451p:plain

  • テストモードで開始する f:id:volpe0104:20190416005500p:plain


  • Fireabese CLI でログイン
$ firebase login
  • Firebase Hosting の設定
    • directory は dist を選択
$ firebase init hosting
  • 2つ目以降のプロジェクトの場合は .firebaserc にプロジェクトを追加 (firebase use --add でも可)
{
  "projects": {
    "default": "hoge-dev",
    "production": "hoge-prod"
  }
}
  • プロジェクトを選択し、デプロイ
$ firebase use production
Now using alias production (hoge-prod)

$ yarn run build
$ firebase deploy

プロジェクトの上限は5つほどらしいが、リクエストフォームで増やしたい理由を伝えれば増やせるとのこと。

Glide を試してみた

Twitter を眺めていたら 簡単過ぎる!GoogleスプレッドシートからPWAアプリを開発できる「Glide」を使ってみた! という面白そうな記事を見つけたので早速試してみた。

Google Spreadsheet をデータとしてスマホ用のアプリを簡単に作れるという。

とりあえずやってみた

確かに簡単にできた。 Oshio Tunings

f:id:volpe0104:20190412092740p:plain

題材はこれまで何回か作ってきた、大好きな押尾コータローさんの楽曲の曲ごとのチューニングがすぐにわかるアプリ。 曲を練習する際にチューニングがパッとわかると便利。おまけに検索機能もデフォルトで付いている。

基本的な作り方は前述で紹介した記事そのもので、スプレッドシートに曲情報をせっせと入力して、Glide 上でどのデータをどこに表示するかを調整するだけ。

こんな感じのスプレッドシートを書いた。 f:id:volpe0104:20190412092735p:plain

UIはいくつかのテンプレートから選択する感じでカッコいいのが簡単にできちゃう。 アルバム画像は自身で運用しているサービス「コタれん」に上がってるデータをへの直リンクを使ったけど、GooglePhotos からでも直リンクがいけたので応用が効きそう。(永続的にいけるかは試していない)

あとちょっと工夫(?)したのは、曲を練習中はどうしても上手い人の演奏動画が見たくなるから Youtube へのリンクボタンを追加した。 f:id:volpe0104:20190412092728p:plain

リンクURLはスプレッドシート上で単純に Youtube への検索クエリを生成しておいたものをボタンに割り当てた。

= "https://www.youtube.com/results?search_query=押尾コータロー " & B2

B2 には曲名が入っている。 PCのブラウザだと Youtube のサイトが開いちゃうけど、スマホだったら Youtube アプリがさっと起動して動画を再生できるからいい感じ。

あと、コメント機能も超簡単に実現できる。このアプリでコメントは使わなそうだけど、曲の感想とか共有するのはアリかも。

他にも地図とかビデオとか部品がいくつかあるので発想次第では簡単に面白いものが作れそう。

テンプレートで発見

ひと通り試したところで、他にもどんなものが作れるのかなとテンプレートを見たら結構複雑な画面遷移でも実現できてる。。。 f:id:volpe0104:20190412092716p:plain

詳細画面からさらにリストを表示するのに 「Inline list」 という Component を使っているけど、自分が作ったアプリには表示されていない。プラグイン的に追加する方法があるのかな? これが使えればかなり凝った画面遷移も出来そう。 スプレッドシートを覗くと隠し列に他のシートとのデータリンクの行が。。。

f:id:volpe0104:20190412092654p:plain

右下にこっそり表示されているヘルプで「Inline list」を調べると以下の動画が見つかった。 https://youtu.be/TH5jk855JrM

これは凄い、、単純にシートにあるデータを表示するだけではなくて、他シートとの関連を書いてあげることでRDB的な使い方も出来そう。

ヘッダー行に 「ヘッダ名=シート名:ヘッダ名」 という感じで書くと別シートのデータを参照してくれて、詳細画面をさらに階層化できそう。 さらに複数要素がある場合は 「ヘッダ名=シート名:ヘッダ名:Multiple」 と書くとリスト表示されるとのこと。これが「Inline list」の正体か! 他にも隠れ機能ありそう。

夢が広がるなぁ。徐々に試してみよう。

Nuxt.js + Firebase で画像ファイルアップロードする

Firestorage に画像ファイルをアップロードしたくなったのでやってみる。

やってることは一般的なファイルアップロードの流れと変わらないが、Firestorage にアップロードする処理は store の action として実装している。

まずは view に form を設置する。 @change イベントハンドラを設定する。

input(type="file", :multiple="false", accept="image/*", @change="detectFiles($event)")

次に methods にファイル選択時のイベントハンドラを定義する。 アップロードするファイル名は他と被らないように uuid ライブラリを使って動的に生成している。 ファイル名とファイル本体を取得したら store の uploadImage へ渡す。

import uuid from 'uuid'
           :
  methods: {
    detectFiles(e) {
      // アップロード対象は1件のみとする
      const file = (e.target.files || e.dataTransfer.files)[0]
      if (file) {
        const fileName = uuid()

        this.$store
          .dispatch('personas/uploadImage', {
            name: fileName,
            file: file
          })
          .then(url => {
            // アップロード完了処理 (ローカルメンバに保存したり)
            this.fileName = fileName
            this.imageUrl = url
          })
      }
    }
  }

store では実際に Firestorage にアップロードする処理を書く。 ここではエラー処理や進捗情報は無視して正常系のみ実装している。 ファイルを上書きしたい場合は、ref() で指定するファイル名に既に存在するファイル名を指定するといい。 取得した url を DB に保持しておけば任意のタイミングで画像を表示できる。

store/persona.js

import firebase from '@/plugins/firebase'
const firestorage = firebase.storage()

export const actions = {
              :
 uploadImage: (context, payload) => {
    return new Promise((resolve, reject) => {
      // firestorage にファイルをアップロード
      const uploadTask = firestorage
        .ref('images/' + payload.name)
        .put(payload.file)
        .then(snapshot => {
           // アップロード完了処理。URLを取得し、呼び出し元へ返す。
           snapshot.ref.getDownloadURL().then(url => {
             resolve(url)
           })
         })
      )
    })
  }
}

これで画像ファイルをアップロードしまくれるぞ!