最近話したこと Rails アプリケーションのデバッグ編

最近Railsのアプリの開発について色々喋ることが多くて、今後も発生しそうだったので書いとく。数ヶ月後の自分用。

前提

  • Docker の上で動いている Ruby on Rails の開発環境がある

デバッグの方法

デバッガとして使えるライブラリは色々あるけど、最近話したアプリケーションでは deivid-rodriguez/pry-byebug を使っているので、その話。 binding.pry というメソッドがブレークポイントとして機能する。止まった後は止まっているコンテキストでオブジェクトの値を確認したり、 step, next, continue を使って処理を動かしたり。最近書かれている binding.pryキホンのキ - SmartHR Tech Blog にも便利情報が載っている。

GitHub - ruby/debug: Debugging functionality for Ruby も最近 binding.break を使うブレークポイントが実装されてそうだった。まだ試してないけど検討はできそう。

pry-byebug の紹介ではないけど、 Rails アプリケーションのデバッグ - Railsガイド にもデバッグの情報はある。

起動している Railsブレークポイントを差して動かすとDocker のコンテナ上で止まるので、コンテナにアタッチする必要がある。RSpecdocker run などのコマンドで実行する場合はコマンドを実行したコンソールで直接 pry-byebug の操作を行える。

RSpec の実行中にアプリケーションログを確認する

テストの実行中はアプリケーションログの出力が抑制されている。config/environments/test.rb の中で config.logger = Logger.new(STDOUT) とか書いとくとアプリケーションログも標準出力に一緒に出てくる。 Request Spec などでテストの中でなに起きてるかわかってない時によく使う。


思い出したら追記する。多分次回はRSpec編。

CarrierWave + carrierwave-aws で aws-sdk-s3 にオプションを渡す

いろいろなことがあり、 CarrierWave とそのストレージライブラリである carrierwave-aws を読んでたのでメモ。主に carrierwave-aws の話。

前提

AWS SDK for Ruby のライブラリのバージョン探すの大変だよね。


つまるところ

例えばアプリケーションで以下のようにCarrierWaveのアップローダーを作ると、S3へのアップロード時にマルチパートアップロードを使用するか判断するファイルサイズの閾値aws-sdk-s3 v1.98.0 時点でのデフォルトである 100MB から変更できる。

class FooUploader < CarrierWave::Uploader::Base
  storage :aws
  
.....

  def aws_write_options
    { multipart_threshold: 20.megabyte }
  end
end

どうなってんの

このライブラリ、 README にはぱっとみ書いてないんだけど CarrierWave::Uploader::Base を継承した uploaderに aws_write_options というメソッドを定義して、ハッシュを渡すと uploader.aws_write_options で読み込んでくれる。このオプションはアップロード時に CarrierWave::Storage::AWSFile#store` で aws-sdk-s3 に渡される。

carrierwave-aws/aws_options.rb at v1.5.0 · carrierwaveuploader/carrierwave-aws · GitHub

      def aws_write_options
        uploader.aws_write_options || {}
      end

ここで定義したアップローダーのオプションを読み込んでくれる

carrierwave-aws/aws_options.rb at v1.5.0 · carrierwaveuploader/carrierwave-aws · GitHub

      def write_options(new_file)
        {
          acl: uploader.aws_acl,
          body: new_file.to_file,
          content_type: new_file.content_type
        }.merge(aws_attributes).merge(aws_write_options)
      end

CarrierWave::Storage::AWSOptions#write_options で読み込んだオプションはここでマージされる

carrierwave-aws/aws_file.rb at v1.5.0 · carrierwaveuploader/carrierwave-aws · GitHub

      def store(new_file)
        if new_file.is_a?(self.class)
          new_file.move_to(path)
        else
          file.upload_file(new_file.path, aws_options.write_options(new_file))
        end
      end

file.upload_file で↑の write_options を渡してますね。

aws-sdk-ruby/file_uploader.rb at c1f4ac742f4dbb66203cc10c45af0019f98b8fde · aws/aws-sdk-ruby · GitHub

aws-sdk-s3 では渡したオプションが Aws::S3::FileUploader コンストラクタ引数の options に入ってくる。という感じ。

      def initialize(options = {})
        @options = options
        @client = options[:client] || Client.new
        @multipart_threshold = options[:multipart_threshold] ||
                               ONE_HUNDRED_MEGABYTES
      end

このあと読む

実はもっとシンプルな指定ができるんじゃないの?ってのが気になってるのでそのとっかかりをメモっとく

carrierwave-aws/carrierwave-aws.rb at v1.5.0 · carrierwaveuploader/carrierwave-aws · GitHub このオプションは add_config で同名のシンボルを引数に渡してそう。

carrierwave/configuration.rb at a3ffc5381e70a4014b61b27b35540aa3b945910d · carrierwaveuploader/carrierwave · GitHub CarrierWave 本体で定義されているメソッドなので、ここらへんでなんやかんやしてそう。

戸建てを建てて引っ越した

f:id:uvb_76:20210901104150j:plain

7月近況 | ikaruga.org でも触れたけど、去年から川崎に戸建てを建てていて、7月に引っ越したので記録を残す。

一旦書いたけど、思い出したら適当に追記するスタイルにしたい。

前提

妻と二人暮らし。私は在宅で仕事をしている。

きっかけ

賃貸アパートに住んでたが、2020年の8月に隣の部屋の治安が悪くなっていくのを感じた。深夜にもいろいろな音が鳴ったり朝4時くらいにお巡りさんがきて事情聴取してたりしてて、妻がかなり参ってたので引っ越しの検討を始めた。

物件さがし

妻の仕事の関係で今の街から離れるつもりはなかったので今住んでいる街の周辺で物件を探すことになった。その周りにはマンションの選択肢はあまりなくて、戸建てをメインに探すことにした。建売の戸建てをSUUMOで探していくつか見に行ったけどあまり良いものは見つからず。良い物件だったとしても20年の借地権の物件だったりして決め手にかけていたところで、まだ前の家がある状態の土地と物件を紹介された。話を聞くと、3階建ての予定で間取りや外装、内装をそこそこ自由にオーダーできる物件であるということで、時間はかかるけど面白そうということで契約することにした。すぐに引っ越せない物件を契約してしまったことで隣の治安の問題を置いてけぼりにしてしまったが、幸運にも隣の住民がその後すぐに引っ越していったので治安の問題は解決されてしまった。また、引越しの時期と賃貸更新の時期が重なっていたのも理由の一つになった。

ローン

たくさん印鑑押して大変だった。健康第一。仕事もちょっと大変で(そう去年自分が書いていたのでそうらしい)気が滅入ってたっぽい。

設計

契約してからは、間取りや外装内装などをオンライン通話やショールームで実際のものを確かめながら決めた。

前述のとおり自由に間取りから決めることができたので、おおざっぱな希望を伝えて参考の間取りをいくつか出してもらい、それをベースに決めていった。やり取りの中で設計担当の方が決まった間取りや議事録を都度PDFで送ってくれたのでとても助かった。iPadに全部入れて気になるときにさっと確認できて便利。やり取りを見返すと10月〜1月はずっと打ち合わせしてたっぽい。

間取り

一度決めたら戻れない所。

水回り

「できれば2Fに水回りを固めたい、もしくは1Fに洗濯物干せると嬉しい」という希望があって、風呂洗濯機を1Fにおくか2Fにおくかで結構悩んだ。2Fに置くとリビングがまあまあ狭くなりそうだったので結局1Fに置いた。

インナーガレージ

車のことは全然考えてなかったけど、将来のことや作業用、来客用のために一応車が入るスペースは確保した。

各階に1つは家具家電搬入用の大きな窓を置く必要がある。 当たり前なのだけれども、枚数が増えれば値段も上がる。あとサッシ。道民からするとアルミはありえん〜って気持ちだったのだけれども、これもまた値段が…結局リビング、寝室の大きな窓を樹脂にした。

ライト

そこまでこだわりはなかったのでダウンライト中心にした。夜に荷物持ったまま帰ってきたときのことを考えて玄関と1F廊下はセンサー付きのダウンライトにして勝手に点くようにした。これは前に住んでた賃貸がそれで体験良かったので参考にした。

電気、ネットワーク

仕事部屋やリビングに余裕もってコンセントを引いてもらったり、空配管、LANケーブルを這わせてもらったり。 当初の参考プランではメディアボックスが3Fの押入れの中に設置されていたのだけれども、熱や無線ルーターの電波やメンテの事を考えて2Fに置くことにした。リビングの隅にデッドスペースがあったので、収納棚をつけてもらいそこにメディアボックスを設置してもらった。これによって棚の一番上にネットワーク系のハードウェアを置いてまとめて管理できるようになった。

f:id:uvb_76:20210901103337j:plain

ショールーム見学、カラーコーディネート

ショールームでの見学、打ち合わせは全て事前予約が必要だった。気軽にいけなくて不便に感じたが、実際見学の際には他のお客さんがいなくてかなり快適だった。担当してくれたプランナーさんによると「事前予約不要だったころはちびっこが動き回ったり外壁のサンプルの取り合いになって全然集中して選べなくて大変〜」とのことだった。

外装、内装の色は妻に大体任せて、自分は「良さそう!」という係に徹した。

引っ越し

ハウスメーカーの斡旋が効くサカイの見積もり見て一発で終わらせた。クレーンが必要など大きなことがない限りは後から費用は発生しませんというところも安心感あった。

大型家具家電の釣り上げや搬入ができるかどうかが引っ越し当日まで不安だった。家が建ってから気がついたのだけれども、家と電柱の距離が思ったよりも近くて搬入時に電線と干渉するかも…?と思ったのがその理由。

引っ越し見積もりの際に地方から応援に来たという営業さんに新居の間取りを見せた上で相談したら「このくらいの家具なら階段でいけますよ〜」とのこと。しかし、引っ越し当日に作業員の方に確認したら間取りも見ずに「階段?無理っすねーまあどうにかしますね」と即答してくれたので色々感じることがあった。実際手際よく外から搬入を完了させていて感心してしまった。こちらとしてはうまく入れる手段がわかって、それらが無事に入ってくれればそれで良い。今後の家具家電の入れ替えがあったときは…その時頑張りましょう。

あと今回は荷物の梱包も業者にお願いした。最終的に60弱のダンボールが積まれていたので、「自分たちでやらずに頼んでよかった…」と二人で心から思った。


ということで物件見始めてから引っ越しまで1年弱。お疲れ様でした。相談に乗っていただいた友人、社の #マンションクエスト チャンネルの皆様ありがとうございました。

最近は机周り揃えたり、土運んだりしてます。

住みだしてからの気づき

  • 家の中に階段あるのが実家ぶりなので、新鮮
    • 在宅で全然動いていないので、引っ越し直後に脚が筋肉痛になった
  • 玄関のライトを自動点灯にしたのはやっぱり正解
  • 野良猫の💩対策は必須

他の人の記事

家を建てるにあたって気にしないといけいないことについては以下のエントリにとても良くまとまっていると思う。

hichihara.hatenablog.com kumagi.hatenablog.com

Ruby 3.0で Module#include の挙動が変わってる

社内で Rubyのしくみの読書会をやっていて、6章の「メソッド探索と定数探索」を読みながらコードを動かしている最中に気がついた。確か以下の記述の検証をしていたときだと思う。

モジュールをインクルードすると、 Rubyはクラスの スーパークラスのリンクトリストに、 そのモジュールのコピーを挿入する

PatShaughnessy. Rubyのしくみ Ruby Under a Microscope (p.150). Kindle 版.

Ruby 2.6.6

$ irb
irb(main):002:0> module M
irb(main):003:1> def hello; end
irb(main):004:1> end
=> :hello
irb(main):005:0> class A
irb(main):006:1> include M
irb(main):007:1> end
=> A
irb(main):008:0> a = A.new
=> #<A:0x00007ffc5f950ef8>
irb(main):009:0> module M2
irb(main):010:1> def foo; end
irb(main):011:1> end
=> :foo
irb(main):012:0> module M
irb(main):013:1> include M2
irb(main):014:1> end
=> M
irb(main):015:0> a.foo
Traceback (most recent call last):
        4: from /Users/ikaruga777/.asdf/installs/ruby/2.6.6/bin/irb:23:in `<main>'
        3: from /Users/ikaruga777/.asdf/installs/ruby/2.6.6/bin/irb:23:in `load'
        2: from /Users/ikaruga777/.asdf/installs/ruby/2.6.6/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
        1: from (irb):15
NoMethodError (undefined method `foo' for #<A:0x00007ffc5f950ef8>)
Did you mean?  for
irb(main):016:0> a.class.ancestors
=> [A, M, Object, Kernel, BasicObject]
irb(main):017:0>

Ruby 3.0.1

irb(main):003:1* module M
irb(main):004:1*   def hello; end
irb(main):005:0> end
=> :hello
irb(main):006:1* class A
irb(main):007:1*   include M
irb(main):008:0> end
=> A
irb(main):009:0> a = A.new
=> #<A:0x00007ffc8a17a460>
irb(main):010:1* module M2
irb(main):011:1*   def foo; end
irb(main):012:0> end
=> :foo
irb(main):013:1* module M
irb(main):014:1*   include M2
irb(main):015:0> end
=> M
irb(main):016:0> a.foo
=> nil
irb(main):017:0> a.class.ancestors
=> [A, M, M2, Object, PP::ObjectMixin, Kernel, BasicObject]
irb(main):018:0>

2.x まではモジュールをインクルードしたクラスの定義後に、インクルードされたモジュールに対して更にモジュールをインクルードしても継承チェーンは反映されなかった。しかし、3.0.0 からは継承チェーンに後からインクルードしたモジュールが反映されるようになる。

ここらへんをみて納得した。

ruby / vscode-rdbg を試す

ruby/debug と連携してデバッグを行える VSCode extension が出てるので試す。

marketplace.visualstudio.com github.com

前提

$code -v
1.57.0
b4c1bd0a9b03c749ea011b06c6d2676c8091a70c
x64
$ruby -v
ruby 3.0.1p64 (2021-04-05 revision 0fb782ee38) [x86_64-darwin19]

準備

debug はプレリリース版をインストールしてねと README にあるので従う。

gem install debug --pre

ためしに以下のようなコードを書いてブレークポイントを貼ってみる

class A
  attr_accessor :x
end

def main
  a = A.new
  a.x = 2
  puts a.x
end

main

f:id:uvb_76:20210618092649p:plain

Debug: Start Debugging and Stop on Entry をコマンドパレットから選択する。初回は .vscode/launch.json が生成される。ちなみに生成しなくても Debug command line からファイルを指定してあげるとそのファイルをデバッガ経由で実行してくれる。単一のファイルのみ確認したいとかだったらこれで十分。

{
  // IntelliSense を使用して利用可能な属性を学べます。
  // 既存の属性の説明をホバーして表示します。
  // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "type": "rdbg",
      "name": "Debug current file with rdbg",
      "request": "launch",
      "script": "${file}",
      "args": [],
      "askParameters": true
    },
    {
      "type": "rdbg",
      "name": "Attach with rdbg",
      "request": "attach"
    }
  ]
}

実行してブレークポイントで停止するとその時点のコールスタックと変数が見れて便利。

f:id:uvb_76:20210618091933p:plain

VSCode デバッガのステップイン等にもちゃんと対応してるし、ウォッチ式で停止している箇所のbindingでコードの実行結果を色々試せて捗りそう。いつも binding,pry を張って試しているので新鮮な気持ちになれた。GUIなデバッガ使うのVC++触ってた時以来かもしれない。

Tumblrのテキスト記事をVuePressで見れるMarkdownに変換するスクリプトを書いた

普段の日記を付ける場所を去年から 鳥人雑技団なんて地元にはない から ikaruga.org に移したのだけれども、過去の記事も移行したかったのでスクリプトを書いた話。

前提

GitHub - ikaruga777/ikaruga.org 移行先はこれです。

    "@vuepress/plugin-blog": "^1.9.3",
    "vuepress": "^1.7.1",

Tumblrブログのエクスポート

エクスポートはTumblr のブログ設定の一番下にある。 f:id:uvb_76:20210608051824p:plain

ここからダウンロードできるエクスポートファイルは以下のような構造を持っている

conversations.zip # メッセージのやりとり
media # 画像とか
├── 36168689520.jpg
├── 36205627811.gif
├── 37911023684.jpg
├── 190878196430_5.jpg
├── 190878196430_6.jpg
├── 190878196430_7.jpg
├── 190878196430_8.jpg
├── 190878196430_9.jpg
└── 190878196430_10.jpg
posts.zip # テキスト

posts.zip の中身は以下のとおり。

.
├── html
│  ├── 35595084788.html
│  ├── 35595101885.html
....
│  ├── 189976946900.html
│  ├── 190103049430.html
│  ├── 190292172880.html
│  ├── 190618623800.html
│  ├── 190682518265.html
│  ├── 190878196430.html
│  └── 613941876100317184.html
├── posts_index.html
└── style.css

posts_index.html にはhtmlのディレクトリにあるhtmlファイルの一覧がずらっと並んでる。

各記事のhtml構造は以下のようになっている。

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <link rel="stylesheet" type="text/css" href="../style.css" />
  </head>
  <body>
    <h1>{{title}}</h1>
    {{body}}
    <div id="footer">
      <span id="timestamp"> March 1st, 2019 2:09am </span>
      <span class="tag">uvb76nikki</span>
    </div>
  </body>
</html>
  • h1 にタイトル
  • 記事のhtml
  • footer にタグと日付

それはそうって感じなのだけれども、TumblrのエディタでMarkdownを使用してようが、出力された後のHTMLがデータとしてエクスポートされるようになっている。

VuePressのfrontmatter付きMarkdown

出力先はVuePressのFrontmatterがついたMarkdown。自分の日記から拝借すると以下のような感じ。

---
title: 2月と3月はじめの近況
date: 2021-03-12 12:01:13+09:00
feed:
  enable: true
layout: post
---
以下本文

変換

というわけでスクリプトを書きなぐった。

gist.github.com

  • h1タグをタイトルとしてなければスキップさせる
  • timestampは雑に Time.parse でいい感じにできた
  • タグ使ってないから無視

解凍後の posts と同じディレクトリに置けば動くはず。nokogiriでbodyの中身切り取ってhtmlのままmdに投げているので1行のhtmlがドカンとmdの本文として吐かれる。汚いけど、HTMLをMarkdownに変換したりフォーマット揃えようとするとSNSの埋め込みタグが大崩壊するので妥協した。今は見れれば良い。

実行すると dist/yyyy/mm/yyyy_mm_dd_title.md の形式で吐かれるので後はよしなに。VuePressのblogプラグインは雑においても認識してくれるので old ディレクトリを切ってそこにまとめた tumblrのコンテンツを移行したいのよね by ikaruga777 · Pull Request #58 · ikaruga777/ikaruga.org · GitHub

dist
├── 2013
│  ├── 06
│  │  ├── Macbook_Air_買った..md
│  │  ├── rvmはsudoつけない.md
...
└── 2020
   ├── 01
   │  ├── 2019_12_28_年末岩手旅行一日目.md
   │  └── 2019_12_29_年末岩手旅行二日目.md
   ├── 02
   │  ├── 2020_02_03_1月近況.md
   │  ├── 2020_02_07_年末岩手旅行三日目.md
   │  └── 2020_02_18_2泊3日で佐渡に行った.md
   └── 03
      └── 2020_3_30 _2月と3月近況.md

こう思ったっす

  • erb意外と手軽
  • SNSの埋め込みタグが厄介
    • 埋め込みタグは一回で読み込み済ませたいVSブログ独自記法が生まれて可搬性を落とす
    • 画像とか本当はリポジトリの中にあるべきだとは思う。
  • これからも何度かこういうことやるなら可搬性は大事そう

これからどうすんの

どうでもいい話

Tumblrの前は無料のレンサバ+Serene Bachでブログ作っておいてたのだけれども、レンサバの障害でデータ全部飛んだらしくインターネットから消え失せた。バックアップも取ってなかったので手元には残っていない。Internet Airchiveにはかろうじて残ってたので最古の記事を見に行ったら2005年の夏の記事が出てきた。2013年くらいまで書いてたっぽい。Tumblrの記事も2013年からあるので、合致してる。ここらへんの記録も全部拾い上げて爪痕にもならない程度の記録にしたい。

Chromeのアドレスバーでの検索の挙動が変わった

Google Chrome 88.0.4324.182 で確認した。

ChromeでRuby関連の検索を楽にする - Re: 醤油の一升瓶じゃあ戦えない のように Chrome検索エンジンを設定することによってアドレスバーから任意の検索クエリを叩くことができる。このアドレスバーを使用したカスタムサーチの仕様が変わっていた。

今までなら {キーワード}{space} でアドレスバーからカスタムサーチに移行できていたのができなくなっていた。スペースの代わりに tab を押すことでカスタムサーチに移行するように挙動が変わったようだった。もとに戻す方法がないか調べていたら以下のページに行き着いた。

www.androidpolice.com

上記ページにあるとおり、 chrome://flags/#omnibox-suggestion-button-rowchrome://flags/#omnibox-keyword-search-button を disabled にすることで今まで通りの挙動に戻すことができた。とはいえ、 github actions とかで調べようとすると勝手に github.com のサーチになるのはうっとおしかったから新しい仕様になれていこうかな〜と思ったり。