Rails 5.2.4 で autosave: true な関連が invalid なときに元レコードの valid? の振る舞いが変わっている件

rack の脆弱性対応があり1、それに対応した Rails を使おうとすると 5.2.4.1 を使う必要がある。のでアプデを試みた。5.2.3 -> 5.2.4.1

マイナーバージョンだし、大丈夫やろw と思いながらとりあえずCIを回してみたところテストが落ちた。はい。

原因を気合で確認したところ、この変更によるものであることがわかった。

github.com

この変更自体について説明するとこんな感じ。例えば、既存レコードについて何らかの理由で Foo.find(1).valid? すると false を返すようなレコードがあるとする。後からバリデーションが追加されたんでも update 文を手でかいたらぶっ壊れたんでもよいけど、とりあえずそういう invalid なレコードがあるとする2。そのときに、それへの autosave: true な関連をもつモデルについてバリデーションの結果が不正なレコードがロード済みであるかによって結果が変わるという話。ロード済みならつられて invalid 扱いになるし、未ロードの場合は valid 扱いになる。これが 5.2.3 までの挙動。この incosistency がいやなので、変更がなさそうなときはバリデーションかけるのやめようや、という変更が 5.2.4 に bug fix としてはいった。その結果、ロード済でも変更してないと valid になってしまうように振る舞いが変わっている。

元 issue の再現コードをちょっと手直ししたのをここにおいておく。

https://github.com/rails/rails/pull/36671 · GitHub

たしかに 5.2.3 -> 5.2.4 でテスト結果が変わっていることが確認できる。しかし実は他のバージョンも試すと(ログも上記の gist に含まれている) 5.2.3 だけではなく 5.1.7, 5.0.7.2, 4.2.11.1 でも落ちていることがわかる。つまり、かなり長い間そうであった挙動がマイナーバージョン変更時に変わったということになる気がしますね。うーん、ちょっと困った。しかも bug fix 扱いなので CHANGELOG にのってないし。

とりあえずはテストのコード変更で対応予定です。


2019-12-20 14:45 追記 && タイトル変えた

github.com

さすがに 4.2 からのコードが動かないのツラいっしょっていう話になったので issue 報告してみました。

github.com

これは似てるけどたぶん元PRの後追い fix のほうの条件でひっかかってるやつだと思う。

regression というタグはついたけどコード変更したほうがいいのかなー、と迷い中。

2019-12-20 15:18

36671 番の変更の内容をもうちょい詳しく書いてる。


  1. https://github.com/advisories/GHSA-hrqr-hxpp-chr3

  2. 再現コードでは save!(validate: false) を使っている。