Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

週刊Railsウォッチ: Kaigi on Rails 2022がCFP公開、Discordの公式Railsサーバーが一般公開ほか(20220627前編)

こんにちは、hachi8833です。今日の暑さはヤバいですね。

週刊Railsウォッチについて

  • 各記事冒頭には🔗でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
  • 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
  • お気づきの点がありましたら@hachi8833までメンションをいただければ確認・対応いたします🙏

TechRachoではRubyやRailsなどの最新情報記事を平日に公開しています。TechRacho記事をいち早くお読みになりたい方はTwitterにて@techrachoのフォローをお願いします。また、タグやカテゴリごとにRSSフィードを購読することもできます(例:週刊Railsウォッチタグ)

🔗Rails: 先週の改修(Rails公式ニュースより)

今回のChangelogは少なめでした。

🔗 MessageVerifierのイニシャライザにurlsafeオプションが追加

ActiveSupport::MessageVerifier.newがオプショナルのurlsafeを受け取るようになった。urlsafe: trueを渡すとurlsafeな文字列を生成する。

verifier = ActiveSupport::MessageVerifier.new(urlsafe: true)
message = verifier.generate(data) # => "urlsafe_string"

後方互換性のため、デフォルトではfalseになる。
Shouichi Kamiya
同PRより

参考: Rails API ActiveSupport::MessageVerifier


つっつきボイス:「MessageVerifierって何だろう?」「ぐぐったらこの記事が出てきた↓」「直接使うことはあんまりない感じでしょうか?」「Active Supportで公開されているので使ってもいいと思いますけど、意識して使ったことはなかったかも」

参考: RailsのMessageVerifierの内部実装を追ってみた - Qiita

RailsではMessageVerifierをCookieで改ざんのチェックに利用していて、署名をつけたメッセージを作成と、メッセージの署名を検証するのに利用されています。
他にはパスワード再発行メールでのトークンなどにも使われているそうです。
同記事より

「改修の方は、これまでMessageVerifierで使われていたBase64.strict_encode6だと生成文字列がurlsafeにならないのでBase64.urlsafe_encode64に切り替えた、なるほど」

# activesupport/lib/active_support/message_verifier.rb#L211
    private
      def encode(data)
-       ::Base64.strict_encode64(data)
+       @urlsafe ? Base64.urlsafe_encode64(data) : Base64.strict_encode64(data)
      end

      def decode(data)
-       ::Base64.strict_decode64(data)
+       @urlsafe ? Base64.urlsafe_decode64(data) : Base64.strict_decode64(data)
      end

参考: module Base64 (Ruby 3.1 リファレンスマニュアル)

「後追いの修正プルリクもマージされていました↓」「そういえばBase64エンコードした文字列の空きは=で埋めたりしますけど、それをオフにしたんですね」

# activesupport/lib/active_support/message_verifier.rb#L213
      def encode(data)
-       @urlsafe ? Base64.urlsafe_encode64(data) : Base64.strict_encode64(data)
+       @urlsafe ? Base64.urlsafe_encode64(data, padding: false) : Base64.strict_encode64(data)
      end

参考: Base64 - Wikipedia

🔗 Active StorageのattachメソッドをAttached::Oneについても修正

#45345で行われたコード変更の後で、ActiveStorage::Attached::OneにもActiveStorage::Attached::Many#attachと非常によく似たattachメソッドがあることに気づいた。単なるリファクタリングではなく、いくつかのブランチで戻り値が変更されたことを考えると、こちらも統一する方がよさそう。
より


つっつきボイス:「#45345は、先週のウォッチで見た#41661のトランザクション内のattach複数回実行と関連していそう(ウォッチ20220613)」「#41661に続いて#45345でActiveStorage::Attached::Many#attachを修正して、一貫性のためにActiveStorage::Attached::Oneも同じように修正したということみたいですね」「ややこしい」

参考: Fix #41661 attaching multiple times within transaction by santib · Pull Request #42300 · rails/rails
参考: Fix #45339 attachments for new record within transaction by santib · Pull Request #45345 · rails/rails

🔗 mini_magickをブロックの外でrequireするよう修正

discussのrubyonrails-coreを参照。
require "mini_magick"は、download_blob_to_tempfileに渡されるブロック内で呼び出されるが、30行目ではブロックの外で使われている↓。

rescue MiniMagick::Error => error

MiniMagick::Errorはブロックの外で定義する必要があり、さもないとdownload_blob_to_tempfileが失敗したときにNameErrorが発生する。しかもこのブロックは決してyieldされないので、mini_magickも決してrequireされない。
自分はこれを実稼働中のアプリで目撃した。ファイルがS3から削除されたためにdownload_blob_to_tempfileが失敗したが、ブロックがまったくyieldされなかった。mini_magickはそれまでrequireされていないのでMiniMagick::Errorが定義されず、現在のエラーが伝搬されずにNameErrorが発生する。
同PRより


つっつきボイス:「Active Storageのmini_magick関連の修正」「mini_magickをブロック内でrequireしてたけど、それを使うエラー処理がブロックの外にあったので意味がなかった、たしかに」

minimagick/minimagick - GitHub

# activestorage/lib/active_storage/analyzer/image_analyzer/image_magick.rb#L11
    private
      def read_image
-       download_blob_to_tempfile do |file|
+       begin
          require "mini_magick"
+       rescue LoadError
+         logger.info "Skipping image analysis because the mini_magick gem isn't installed"
+         return {}
+       end

+       download_blob_to_tempfile do |file|
          image = instrument("mini_magick") do
            MiniMagick::Image.new(file.path)
          end
          if image.valid?
            yield image
          else
            logger.info "Skipping image analysis because ImageMagick doesn't support the file"
            {}
          end
+       rescue MiniMagick::Error => error
+         logger.error "Skipping image analysis due to an ImageMagick error: #{error.message}"
+         {}
        end
-     rescue LoadError
-       logger.info "Skipping image analysis because the mini_magick gem isn't installed"
-       {}
-     rescue MiniMagick::Error => error
-       logger.error "Skipping image analysis due to an ImageMagick error: #{error.message}"
-       {}
      end

[Rails] MiniMagickでPDFのページ数を取得するときはフォントエラーに注意!

🔗Rails

🔗 Discordの公式Railsサーバーが一般公開(Rails公式ニュースより)


つっつきボイス:「少し前にRailsリポジトリで古いプルリクの自動削除をやめてRails issuesチームが新たに創設されていましたね(ウォッチ20220523)」「その続きとして、Discordで公式Railsサーバーを一般公開したそうです↓」「最近こういうのにDiscordをすごくよく使うようになってきた印象がありますね」

参考: discord.com/invite: Ruby on Rails

Discordアプリがなくてもブラウザであっさり参加できました。generalチャンネルで最も古い書き込みは2022/05/19なので、新たに作ったようです。

参考: Discord | 会話や交流が楽しめるプラットフォーム

「既存のRuby on Rails Discussionsも引き続きサポートに使うそうです↓」

参考: Latest rubyonrails-talk topics - Ruby on Rails Discussions

🔗 RSpecで引数に特定の値が渡された時だけスタブする


つっつきボイス:「引数が特定の値のときだけスタブする方法ですか」「allow(shop).to receive(:sell).and_call_originalを書いてから次のallow(shop).to receive(:sell).with('banana').and_return(nil)を書かないといけない: 自分はあまりこういう書き方はしないけど、たしかに可能ですね」

# 同記事より
describe 'Shopper#buy_fruits' do
  let(:shop) { Shop.new }

  before do
    allow(shop).to receive(:sell).and_call_original
    allow(shop).to receive(:sell).with('banana').and_return(nil)
  end

  it do
    shopper = Shopper.new
    expect(shopper.buy_fruits(shop)).to eq ['apple', nil, 'orange']
  end
end

「ただ、この書き方を使い始めるとスタブメソッドの呼び方次第でうまくいったりいかなかったりすることがあるので、正しく動作しているかどうかを確認するのが少し面倒になるかな」「なるほど」

🔗 Kaigi on Rails 2022が10月にオンライン開催、CFPを公開


つっつきボイス:「お、Kaigi on Rails 2022🎉」「10/21〜10/22なので、9月のRubyKaigi 2022の翌月ですね」

参考: Kaigi on Rails 2021
参考: Kaigi on Rails

「Kaigi on Rails 2022はオンラインのみだそうです」「日本はまだ現地開催があまり復活していない感じですけど、主催側の負担が大きくなりますし、悩ましいところでしょうね」「そうなんですよね...」

🔗 Webアプリで忘れがちなセキュリティ対応5つ(RubyFlowより)


つっつきボイス:「ベストプラクティスというより、思いついた順のメモ書きっぽい記事かな」「少しとりとめもない感じですね」


「このサイトでセキュリティヘッダーをチェックできるそうです↓」「Railsデフォルトのセキュリティヘッダーのままだと、こういうサイトでたまに警告が出たりしますね」「そういえばGitHub公式のsecure_headersというgemもありますね」

参考: Analyse your HTTP response headers

github/secure_headers - GitHub


「メールのセキュリティは、SPFやDKIMやDMARCをチェックすべきという定番の話」「これもチェックサイトがあるんですね↓」

参考: インターネット用語1分解説~SPFとは~ - JPNIC
参考: インターネット用語1分解説~DKIMとは~ - JPNIC
参考: インターネット用語1分解説~DMARCとは~ - JPNIC

参考: SPF record Checker | SPF record Tester - Mimecast | DMARC Analyzer
参考: DKIM record Checker | Test your DKIM record - DMARC Analyzer
参考: DMARC record Checker | DMARC record Tester - Mimecast | DMARC Analyzer


「ファイル転送のセキュリティ: たとえばこちらで制御できないサードパーティのサーバーを経由するとファイルが残ってしまう可能性があるので、どこまでセキュアに転送すべきかという問題は常に悩ましい」「永遠の課題ですね」

「magic-wormholeはエンドツーエンドのファイル転送ツールか: 似たようなツールは他にもあると思いますが、こういうのを使いたい場合があるのはわかる」

magic-wormhole/magic-wormhole - GitHub


「最後はAWSのIAMポリシーの話」「IAMポリシーで本当に必要な権限だけを付与しようとすると、いくらでも手間がかかる、かといって楽に済ませようとするとセキュリティが粗くなってしまう」「そこですよね」「AWS公式のチュートリアルもそこまで厳密ではありませんし」

参考: IAM でのポリシーとアクセス許可 - AWS Identity and Access Management
参考: IAM のチュートリアル - AWS Identity and Access Management

「IAMポリシーは、S3のような比較的シンプルなものでも、たとえばリストアクセスを許可しないとライブラリが動かなかったりするんですよ: ListAllMyBucketsを許可しないとバケットの存在をチェックできないとか」「あ〜」「IAMポリシーは知らないとわからないものも多いし、挙動が期待と違うことも割とあります」「う〜む」「今は特定用途のIAMポリシーについてはベストプラクティスも出てきているので、そういうのを使うしかないのかもしれないという気持ちです」

「あとIAMポリシーで大事なのは、AWSアカウントベースで分割しておくことでしょうね: 記事のこの設定↓のように"Resource"ベースでやると後々手間がすごいことになる」「なるほど」

# 同記事より
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::your-bucket-name"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:DeleteObject",
                "s3:PutObjectAcl"
            ],
            "Resource": [
                "arn:aws:s3:::your-bucket-name/*"
            ]
        }
    ]
}

「たとえば上のポリシーの"Resource"は、下はyour-bucket-name/*のように/*を付けないといけないのに、上のリストバケットに/*を付けたら動かない、というふうに知らないとわからない細かい違いが多いんですよ」「/*のあるなしを指定するために同じことを2回も書かないといけないとは...」


前編は以上です。

バックナンバー(2022年度第2四半期)

週刊Railsウォッチ: VSCodeでRubyコード実行結果を表示、rubygems.orgがgem作者に多要素認証を呼びかけほか(20220621後編)

今週の主なニュースソース

ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSやruby-jp SlackやRedditなど)です。

Rails公式ニュース

RubyFlow

160928_1638_XvIP4h


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。