- 開発
週刊Railsウォッチ(20190902)Ruby 2.6.4セキュリティ修正リリース、スライド「All About Ruby in 2019」、Shrine gem 3.0に入る新機能ほか
こんにちは、hachi8833です。ついさっきruby-jp Slackのワークスペースアイコン↓が見ている目の前で突然変わってびっくりしました😳。おめでとうございます!🎉
その後ちょっぴりリサイズしたようです↓。
- 各記事冒頭には⚓でパーマリンクを置いてあります: 社内やTwitterでの議論などにどうぞ
- 「つっつきボイス」はRailsウォッチ公開前ドラフトを(鍋のように)社内有志でつっついたときの会話の再構成です👄
- 毎月第一木曜日に「公開つっつき会」を開催しています: お気軽にご応募ください
※今回のウォッチは分割していません
※今回のつっつきはSlackベースで行いました
⚓週刊Railsウォッチ「公開つっつき会」第14回のお知らせ(無料)
第14回目公開つっつき会は、9月5日(木)19:30〜にBPS会議スペースにて開催されます。皆さまのお気軽なご参加をお待ちしております🙇。
⚓Rails: 先週の改修(Rails公式ニュースより)
公式の更新情報のほとんどを先週の「先週の改修」で先取りしていました😋。今回も6-0-stableの更新を中心に見てみました。
他に、6.0.1マイルストーンのclosedからも見繕いました。
⚓(6-0-stable、master)fork後にConnectionPool::Reaper
が親のコネクションを刈り取る問題を修正
先週の#36999や#36998に関連していそうです。また「attr_reader :pools
に依存しないようにした」ともあります。
# activerecord/lib/active_record/connection_adapters/abstract/connection_pool.rb#L332
private
def spawn_thread(frequency)
Thread.new(frequency) do |t|
running = true
while running
sleep t
@mutex.synchronize do
- @pools[frequency].select!(&:weakref_alive?)
+ @pools[frequency].select! do |pool|
+ pool.weakref_alive? && !pool.discarded?
+ end
+
@pools[frequency].each do |p|
p.reap
p.flush
rescue WeakRef::RefError
end
if @pools[frequency].empty?
@pools.delete(frequency)
@threads.delete(frequency)
running = false
end
end
end
end
end
...
def discard! # :nodoc:
synchronize do
- return if @connections.nil? # already discarded
+ return if self.discarded?
@connections.each do |conn|
conn.discard!
end
@connections = @available = @thread_cached_conns = nil
end
end
+ def discarded? # :nodoc:
+ @connections.nil?
+ end
...
つっつきボイス:「この辺はGC系とかも絡んでいるようでデバッグが大変そうなところだなあ」
⚓content_type=
の追加部分が落ちないよう修正
# actionpack/lib/action_dispatch/http/response.rb#L420
private
- ContentTypeHeader = Struct.new :mime_type, :extra, :charset
- NullContentTypeHeader = ContentTypeHeader.new nil, nil, nil
+ ContentTypeHeader = Struct.new :mime_type, :charset
+ NullContentTypeHeader = ContentTypeHeader.new nil, nil
+
+ CONTENT_TYPE_PARSER = /
+ \A
+ (?<mime_type>[^;\s]+\s*(?:;\s*(?:(?!charset)[^;\s])+)*)?
+ (?:;\s*charset=(?<quote>"?)(?<charset>[^;\s]+)\k<quote>)?
+ /x # :nodoc:
def parse_content_type(content_type)
if content_type && match = CONTENT_TYPE_PARSER.match(content_type)
- ContentTypeHeader.new(match[:type], match[:extra], match[:charset])
+ ContentTypeHeader.new(match[:mime_type], match[:charset])
else
- ContentTypeHeader.new(content_type, nil)
+ NullContentTypeHeader
end
end
つっつきボイス:「この間からcontent_type周りが繰り返し修正されているようですが、ちょっとややこしいことになってそう?」「これは@kamipoさんが貼ってくれてるこのPR(#35549)↓が発端みたいすね: この辺は使ってる人たちがテストしないとなかなか踏まなそうなところ」「通常の使い方をしている分には問題はないんでしょうか?」「いや、そもそも既存のコードで使ってた人たちに問題が出たというものだと思います: ただ、今回のIssueを踏むような使い方をしている人たちがそれほど多くなくて発見が遅くなったみたいな話だと思う」
Content-Typeヘッダーに、
charset
以外のオプションパラメータが含まれる可能性がある。
このヘッダー行の有無を示す例として、text/csv typeに以下のようなheader
パラメータがあるとする。
Content-Type: text/csv; charset=utf-16; header=present
この種のオプションパラメータを
#charset
から除外するため、このPRで#parse_content_type
の実装を変更した。
#35549より大意
@kamipoさんのレスには「#33549でdeprecation期間を置かずに変更したのは急ぎすぎだった」とあります。
⚓(6.0.1)attachables.nil?
条件を除去
# activestorage/lib/active_storage/attached/model.rb#L91
def has_many_attached(name, dependent: :purge_later)
generated_association_methods.class_eval <<-CODE, __FILE__, __LINE__ + 1
def #{name}
@active_storage_attached_#{name} ||= ActiveStorage::Attached::Many.new("#{name}", self)
end
def #{name}=(attachables)
if ActiveStorage.replace_on_assign_to_many
attachment_changes["#{name}"] =
- if attachables.nil? || Array(attachables).none?
+ if Array(attachables).none?
ActiveStorage::Attached::Changes::DeleteMany.new("#{name}", self)
else
ActiveStorage::Attached::Changes::CreateMany.new("#{name}", self, attachables)
end
else
- if !attachables.nil? || Array(attachables).any?
+ if Array(attachables).any?
attachment_changes["#{name}"] =
ActiveStorage::Attached::Changes::CreateMany.new("#{name}", self, #{name}.blobs + attachables)
end
end
end
CODE
つっつきボイス:「リファクタリングでしょうか?」「これはリファクタリング&読みやすさに倒したみたいな感じみたいですね: PR読めばそんなに難しいこと書いてない感じ」
⚓(6.0、6.0.1)connected_to
でwhile_preventing_writes
を呼ぶようになった
while_preventing_writes
をconnected_to
から直接呼び出すようにしたアプリケーションの作者がデータベース切り替えミドルウェアを使って
connected_to
を明示的に呼び出したい場合がある。アプリは書き込みをオフにできるが、connected_to(role: :writing)
を呼び出すまではオンに戻らない。
アプリはこの変更によって、(明示的に書き込みをオフに場合を除いて)書き込みを許可したいロールが書き込みを行っているかどうかを仮定することで修正できる。
CHANGELOGより
# activerecord/lib/active_record/connection_handling.rb#L116
- # When using the database key a new connection will be established every time.
- def connected_to(database: nil, role: nil, &blk)
+ # When using the database key a new connection will be established every time. It is not
+ # recommended to use this outside of one-off scripts.
+ def connected_to(database: nil, role: nil, prevent_writes: false, &blk)
if database && role
raise ArgumentError, "connected_to can only accept a `database` or a `role` argument, but not both arguments."
elsif database
if database.is_a?(Hash)
role, database = database.first
role = role.to_sym
end
config_hash = resolve_config_for_connection(database)
handler = lookup_connection_handler(role)
handler.establish_connection(config_hash)
with_handler(role, &blk)
elsif role
- with_handler(role.to_sym, &blk)
+ if role == writing_role
+ with_handler(role.to_sym) do
+ connection_handler.while_preventing_writes(prevent_writes, &blk)
+ end
+ else
+ with_handler(role.to_sym, &blk)
+ end
else
raise ArgumentError, "must provide a `database` or a `role`."
end
end
つっつきボイス:「connected_to
にrole: :writer
+ prevent_writes
をしようと思ったときにrace conditionしちゃう的な話なのか↓」「確信はないけどこの辺のやつで外側のAR::Base.connected_to
と内側のAR::Base.connection_handler
で別のDBコネクション取っちゃうみたいなケースがあったのかなあ?」
# activerecord/lib/active_record/middleware/database_selector/resolver.rb#L46
private
def read_from_primary(&blk)
- ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role) do
- ActiveRecord::Base.connection_handler.while_preventing_writes(true) do
- instrumenter.instrument("database_selector.active_record.read_from_primary") do
- yield
- end
+ ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role, prevent_writes: true) do
+ instrumenter.instrument("database_selector.active_record.read_from_primary") do
+ yield
end
end
end
⚓番外: メンテナンスポリシーの記載を明確にした
# guides/source/maintenance_policy.md#L67
For severe security issues all releases in the current major series, and also the
- last major release series will receive patches and new versions. The
+ last release in the previous major series will receive patches and new versions. The
classification of the security issue is judged by the core team.
つっつきボイス:「これはまあ書いてあるとおりということで☺️」
参考: Ruby on Rails のメンテナンスポリシー - Rails ガイド
上の修正に基づくと、Railsガイドの該当箇所は以下のようになります。後ほどRailsガイドを更新します(#883)。
重大なセキュリティ問題については、最新のメジャーなシリーズにおけるすべてのリリースと、前回のメジャーなシリーズの最後のリリースに対してセキュリティパッチと新バージョンを提供します。セキュリティ問題の重大性の分類はコアチームによって行われます。
つまり今回の場合、Rails 6がリリースされたことで、Rails 5.1.z以前についてはセキュリティパッチや新バージョンは提供されなくなったということになります。
⚓Rails
⚓Jetsの実験的Rails互換「アフターバーナーモード」機能
まだexperimentalですが、RackをLambda実行コンテキストで起動することで、Railsアプリを無改造でデプロイできるようにする試みだそうです。
参考: AWS Lambda 実行コンテキスト - AWS Lambda
注意:
- RailsプロジェクトのGemfileにjetsを追加しないこと
- Railsアプリを必ずしもそのままサーバーレス化できるとは限らない
- たとえばファイルや画像をファイルシステムにアップロードするアプリはそのままでは無理
- Lambdaレイヤのサイズは250MBに制限されている
- Railsの基本gemだけで146MBぐらいにはなる
- 複雑なRailsアプリについてはJetsのメガモードも検討
- アフターバーナーモードよりはJetsで直接アプリにする方が一般におすすめ
参考: AWS Lambda の制限 - AWS Lambda
つっつきボイス:「Jetsのafterburner modeはかなり初期からexperimentalとして公式ドキュメントにはありましたね: ただ、どれくらいまともに使われてるのかが謎すぎるので全然触ってない」「あ、そんなに前からあったんですね😅」「そもそもRailsをそのまま変換して動くケースの方が極レアだと思うので、そこまで魅力は感じなかったなあ(誰か人柱している人がいればレポートは見てみたいけど)」
「まあ特に魅力に感じなかったので「夢の試みだなあ」くらいにしか見てなかった😆」「アフターバーナー、見るからに重そう...」「Railsに必要なRack Middlewareを毎回ロードするということを考えるとちょっと厳しすぎるだろう感はありますねえ」
⚓Shrine gem 3.0で予定されている新機能(RubyFlowより)
- ミュータブルなstructからの切り離し(Repositoryパターンに対応するため)
- derivativesプラグイン
- backgroundingプラグイン
- 一時ストレージをスキップする機能
- ファイル取り出しの高速化
- 永続化APIを複数のプラグインで標準化
つっつきボイス:「Shrine、Active Storageに押されて更新やめちゃうとかも心配してたけど、開発続行してくれる感じなんですね: 既存システムのアップグレードパスとしてもありがたいし、Active Storageでできない機能とかもちょいちょいありそうだしありがたい話だ🙏」「記事には『現行のShrineはActive Recordとかにはよく合う設計だが、Hanamiとかに合わないのでstructを切り離した』とありました」「あーなるほど。確かにRails専用ってわけじゃないですもんね、それは分かる😋」「今後のメンテも期待できそうですね❤️」
- サイト: Shrine
⚓Rails 6のWebpackerを理解する(Awesome Rubyより)
- デフォルトで
app/javascript
に置かれる app/javascript/packs
にはapplication
packが置かれるbin/webpack-dev-server
でライブリロードできる- production環境では
assets:precompile
タスクにwebpacker:compile
が追加される javascript_pack_tag
ヘルパーメソッドはアセットパイプラインのjavascript_link_tag
と同等
つっつきボイス:「記事の行間が開きすぎてて読みにくい💦」「😆」「Understandingとあるけど割と簡単なことしか書いてない気もするので、いわゆる「完全に理解した」的な記事かな😇」「Webpackerの「Rails 6での変更点」を理解してみた的な?」「あ、たしかにRails6になって変わった部分もピックアップされてますね: 5.2からのmigration path的にはありがたい話なのかも」「Railsガイドにはありそうですが、変更点までは網羅されてないかもですね(後で見ます)」
意外にもRailsガイドにはWebpackerのまとまった記述がありませんでした😳。アップグレードガイドでWebpackerについてごく簡単に触れられている程度です↓。
参考: 2.1 Webpackerの利用について -- Rails アップグレードガイド - Rails ガイド
⚓Ruby
⚓Ruby 2.6.4がリリース: セキュリティ修正(Ruby公式ニュースより)
- リリース情報: Ruby 2.6.4 Released
「RDoc に含まれる jQuery においてクロスサイトスクリプティング(XSS)の脆弱性が発見されました。」
「RDoc 自体を修正しても、既に生成済みの HTML ドキュメントの脆弱性は解消されません。 (略) 該当の HTML ドキュメントを再生成してください。」 https://t.co/UsqXc07Pkw— Junichi Ito (伊藤淳一) (@jnchito) August 28, 2019
つっつきボイス:「このツイート見るとRDocの再生成も必要...😅: RDoc生成を抑制していれば大丈夫?」「Doc生成してしかもそれをPublic公開してない限りは問題ないやつですね: 使ってる人が少ない機能とかだとなかなか発見が遅れるやつ」
主にgemの作者にとって影響がありそうですね。
なお、現在は--no-ri
や--no-rdoc
ではなくno-document
で抑制すると今頃知りました↓。
参考: ruby - How to make --no-ri --no-rdoc the default for gem install? - Stack Overflow
参考: gemrcの--no-riと--no-rdoc、deprecatedなoptionなのでみなおしたほうがいいかもですよ - Qiita
⚓Bundler 2.1.0pre.1リリース
つっつきボイス:「かなり内部をアップデートしたそうです」「マイナーバージョンアップでpreを踏むの、慎重でありがたいすね: Bundlerの挙動がおかしくなると世の中のRailsエンジニアのあちこちから悲鳴あがるし、じっくり検証&フィードバック期間があるのはありがたい🙏」
後でリリースノートを見ると機能とバグフィックスがたくさん載っていますが、機能のみざっと見てみました。
config
コマンドをサブコマンドで再実装bundle plugin list
を追加bundle lock --gemfile
フラグを追加- ローカルgitリポジトリソースを指定する
--local_git
オプションを追加(プラグインインストール用) quiet
フラグをインラインbundlerに追加prefer_patch
設定を導入(bundle update
の振る舞いをbundle update --patch
のようにする)Bundler.original_system
とBundler.original_exec
を導入bundle info GEM
を追加(旧bundle show GEM
に相当)- Gemfileのgemグループのリストを表示する
bundle list
を導入(従来はbundle show
のエイリアスだった) bundle outdated --filter-strict
を導入(bundle outdated --strict
のエイリアス)bundle add
に:git
オプションと:branch
オプションを追加ruby_26
を:platform(s)
DSLに有効な値として追加bundle package
で提供されているすべての機能をbundle cache
に含めた- 新しいgemテンプレートを改善
bundle gem
に--[no-]git
オプションを追加(ソース管理しないgemを生成、単一リポジトリなどで有用)
⚓スライド「All About Ruby in 2019」
- サイト: Developers Summit 2019 FUKUOKA -- 8/29(木)に福岡で開催されました
つっつきボイス:「Ruby 2.3からの差分の歴史とかもさらっとまとまっててありがたいな: これは良い👍」「スライドで情報が完結していてありがたいです🙏」
「RubyのDockerイメージ、Docker Community版しか知らなかったけどRubyコアチーム版もあるのか↑: 確かにDocker Community版のコンテナは実は色々盛りだくさんに入っているので、pureなRubyを動かすだけならもっと軽いイメージの選択肢はあるなと思っていた(その代わり、gem install rails
がすぐにできるように色々入ってる利点もある): まだExperimentalって書いてあるからいまいち詳しいことはわからないけど」
- Ruby Dockerイメージ(Docker Community版): ruby - Docker Hub
- Ruby Dockerイメージ(コアチーム版)rubylang/ruby - Docker Hub
「コアチーム版のメンテナーはmrknさんなのね↓」
「DockerHub版のDockerfile↑はなんかちょいちょいHackぽいこともやってるように見えるのでrubylang/ruby の方が整理されている感じはある、と思ったら環境変数が違うとかちゃんとスライドに書いてあった↓」
スライドには、他にRubyのPlaygroundサイトなども紹介されています。要チェックだと思います😋。
- Playground: TryRuby: Learn programming with Ruby
なお、このスライドは以下のツイートで知りました。
Ruby2.7新機能の紹介
しかし、発表したその日に紹介されている新機能のうち2つも仕様変更してしまったのは申し訳ないと感じている(スライドは更新済み)#AnyPickshttps://t.co/1PU8kgR9vO
— Yukihiro Matsumoto (@yukihiro_matz) August 29, 2019
スライドによると、発表後の2つの変更点は以下でした。
- numbered parameterの記法が
@1
から_1
へ
- パイプライン演算子
|>
をいったんご破算(記法の変更も含め将来に再検討するかも)
⚓その他Ruby
ランボー怒りの 44 files changed, 369 insertions(+), 246 deletions(-) https://t.co/X657OHEZbK
— 7594591200220899443 (@shyouhei) August 27, 2019
つっつきボイス:「RubyのソースでANYARGSとかいうのが使われすぎてたのを修正したそうです」「ANYARGSだけじゃなくてvoid*
とかも駆逐されたりしていて相当でかい修正だな。しゅごい😳」「RubyのCのソース、表記スタイルが長年にわたってばらつきまくっているという話が以前ありましたけど、今からだと修正量が莫大になっちゃいそうだからなかなか行われないのかな...」「ソースのスタイルに大きく手を入れると開発者脳内にある関数名とかマクロ名とかのポインタがロストしてしまうので、一部のメンバーが中心になってコード書いてるようなプロジェクトでは変化させないほうが全体効率が良い、とかはあるかもですね☺️」
⚓クラウド/コンテナ/インフラ/Linux/Serverless
⚓Google App Engineスタンダード環境でRuby 2.5をサポート(ベータ)
つっつきボイス:「GAEは正直あんまり詳しくないけど、AWSのLambda Layerみたいな自由度あるのかなあ🤔」「記事のリンクによるとApp Engineには「スタンダード環境」と「フレキシブル環境(Ruby対応済み)」というのがあるそうです↓」
参考: App Engine 環境の選択 | App Engine ドキュメント | Google Cloud
「GAEはstarndard / flexibleで全然環境自体が違うんですね: Lambdaは実行環境自体はAWS提供の環境でもユーザーの作ったLambda Layerでも基本的に同じはず(Firecrackerだっけかな)」「GAEのflexible は完全にDockerみたいなので、LambdaとかGAE standardと比べるには不利すぎるかな🤔」
参考: Firecracker – サーバーレスコンピューティングのための軽量な仮想化機能 | Amazon Web Services ブログ
追記(2019/09/04)
Quora: (3) とうとうGoogle App EngineでRubyが標準サポートになりましたが、心境のほどはいかがでしょうか?に対するYukihiro Matsumotoさんの回答 - Quora
⚓JavaScript
⚓知っておきたいJavaScriptの新機能7つ
つっつきボイス:「はてブで見つけました: privateの記法がキモがられてるっぽいです」「optional chaining(?.
)はなんかで見ましたね: Rubyで言う&.
(ぼっち演算子)的な」「クライアントはブラウザ依存あるから、これらの機能が使えるようになるまでまだ時間かかりそうだけど、サーバーサイドJSで使う分には問題ないから知っておいてもよさそう😋」
// 同記事より
// privateフィールドは'#'で始まらなければならない
// classブロックの外部からはアクセスできない
class Counter {
#x = 0;
#increment() {
this.#x++;
}
onClick() {
this.#increment();
}
}
const c = new Counter();
c.onClick(); // 動く
c.#increment(); // エラーになる
// 同記事より: optional chaining
const stop = please?.make?.it?.stop;
⚓その他
⚓やはり名前が大事
「適切な名前をつけることができたら、(プログラミングの)設計は8割できたようなもの」
'98年にコーディング始めた時に師匠に叩き込まれたのはこれと「機能の直交性」でした!— Shoemaker Smith (@csmith_tokyo) August 29, 2019
つっつきボイス:「以前のウォッチでも、コーディングで一番時間がかかるのが「名前付け」という記事を散りあげた覚えがあります」「命名はコーディングというよりは『設計』なんですよね: 名は体を表すの通りなので、適切な命名がされればあとは純粋なロジックを書くのに集中できるという」
⚓番外
⚓iPS細胞で視力を取り戻す
https://www.youtube.com/watch?v=zNKYudKmXsQ
つっつきボイス:「20年もしたら普通になってきそうですね」「この辺はもう治験に入ってるんだなあ: 未来感ある🚀」「度胸さえあれば、白内障になったときにこれ↓試してみたい気も😆」
参考: 3Dプリンターで完璧に機能する目「バイオニックアイ」を作り出す研究 - GIGAZINE
今回は以上です。
おたより発掘
基本的にJSは破壊的変更が許されない言語。
`$` `_` あたりは今まで通常のプロパティ名として扱えたため、修飾子として予約語にできない記号です。可読性を考慮すると `@` `#` あたりが候補にあがったものの、DecoratorのProposalとして `@` の使用が提案されているため、残る `#` が採用された経緯が— Jaga Apple (@jagaapple_tech) September 2, 2019
バックナンバー(2019年度第3四半期)
- 20190821-2/2後編 11のgemにバックドア、ruby-jp Slackがとてもアツい、Fullstaq Rubyでチューンアップ、HTTPサービス監視chaoほか
- 20190819-1/2前編 祝: Rails 6がついにリリース、RailsガイドもRails 6に対応、Arelはpublicだったかほか
- 20190806-2/2後編 RSpec CopのLeakyConstantDeclaration、serveoでゼロコンフィグ公開、RuboCopのPerformance/RegexpMatch改修ほか
- 20190805-1/2前編 Rails 6のActive Recordは速くなった、Windows WSL2+VSCodeでのRails開発、Martin Fowler記事ほか
- 20190730-2/2後編 Docker 19.03の新機能に注目、ngrokはスゴい、redis-namespaceほか
- 20190729-1/2前編 Rails 6のリリースは近そう?、Evil MartiansのRails+Docker記事、Railsパフォーマンス測定ほか
- 20190723-2/2後編 Rails 6 rc2がリリース、「MySQLパフォーマンスチューニングTips」が超便利、Aurora Serverlessほか
- 20190722-1/2前編 Rails 6エラー画面の改良点、Dateを四捨五入できるtime_calc、Rackミドルウェアのデザインパターンほか
- 20190717-2/2後編 NFSのよさとは、Linuxカーネル5.2リリース、Puppeteerでメモリリーク検出ほか
- 20190709-2/2後編 strong_password v0.0.7がハイジャックされていた、TerraformとCloudFormation、CSSの設計ミスリストほか
- 20190708-1/2前編 ActiveRecord::FixtureSetがめちゃ強くなってた、MacだとRubyが遅い理由、Puma 4登場ほか
- 20190701 RMagickのメモリ使用量が劇的に改善、インスタンス変数の定義順で速度が変わる?、GitLab CIランナーをローカルで回すほか
今週の主なニュースソース
ソースの表記されていない項目は独自ルート(TwitterやはてブやRSSなど)です。