SVX日記
2024-03-06(Wed) SinatraのPOSTでrequest.body.rewindが動かない
先日、Sinatraに認証機能を付けたのだが、その際にbundle addをやり直してGem関係を最新にしたらPOSTの内容がreadできなくなってしまった。
NoMethodError at / undefined method `rewind' for #<Rack::Lint::Wrapper::InputWrapper:0xXXXX @input=#<StringIO:0xXXXX>>
なんて出る。何かやらかしたかと思ったが、特段イジっていない。該当のコードは「request.body.rewind」らしいのだが、だいぶ前なので、なんでそんなコードを書いたのか覚えていない。が、どうもSinatraのオフィシャルサイトのサンプルコードから持ってきていたようだ。
post "/api" do
request.body.rewind # in case someone already read it
data = JSON.parse request.body.read
"Hello #{data['name']}!"
end
それなのに動かないってどういうことよ。と思って追跡していくと、どうもRackのバージョンアップの影響らしい。Gemfileの記述を戻すと動く。「request.body」のメソッドを表示させてみると、実際に変わってしまっていて「rewind」メソッドがなくなってる。そら動かん。bundleの仕組みは、今回のようにバージョンアップの影響で動かなくなることを防ぐ意図もあるのだが、実際にこんなことあるんやな。
# 動くバージョン
request.body: #<Rack::Lint::InputWrapper:0xXXXX @input=#<StringIO:0xXXXX>>
request.body.methods: [:!, :!=, :!~, :<=>, :==, :===, :__id__,
:__send__, :assert, :class, :clone, :close, :define_singleton_method,
:display, :dup, :each, :enum_for, :eql?, :equal?, :extend, :freeze,
:frozen?, :gem, :gets, :hash, :inspect, :instance_eval,
:instance_exec, :instance_of?, :instance_variable_defined?,
:instance_variable_get, :instance_variable_set, :instance_variables,
:is_a?, :itself, :kind_of?, :method, :methods, :nil?, :object_id,
:private_methods, :protected_methods, :public_method, :public_methods,
:public_send, :read, :remove_instance_variable, :respond_to?, :rewind,
:send, :singleton_class, :singleton_method, :singleton_methods, :tap,
:then, :to_enum, :to_json, :to_s, :yield_self]
request.body.read: "key=value1&key=value2&commit=do+POST+test"
# 動かないバージョン
request.body: #<Rack::Lint::Wrapper::InputWrapper:0xXXXX @input=#<StringIO:0xXXXX>>
request.body.methods: [:!, :!=, :!~, :<=>, :==, :===, :__id__,
:__send__, ※, :class, :clone, :close, :define_singleton_method,
:display, :dup, :each, :enum_for, :eql?, :equal?, :extend, :freeze,
:frozen?, :gem, :gets, :hash, :inspect, :instance_eval,
:instance_exec, :instance_of?, :instance_variable_defined?,
:instance_variable_get, :instance_variable_set, :instance_variables,
:is_a?, :itself, :kind_of?, :method, :methods, :nil?, :object_id,
:private_methods, :protected_methods, :public_method, :public_methods,
:public_send, :read, :remove_instance_variable, :respond_to?, ※,
:send, :singleton_class, :singleton_method, :singleton_methods, :tap,
:then, :to_enum, :to_json, :to_s, :yield_self]
request.body.read: ""
$ gem search '^rack$' --all
rack (3.0.9.1, 3.0.9, 3.0.8, 3.0.7, 3.0.6.1, 3.0.6, 3.0.5, 3.0.4.2,
3.0.4.1, 3.0.4, 3.0.3, 3.0.2, 3.0.1, 3.0.0, 2.2.8.1, 2.2.8, 2.2.7,
2.2.6.4, 2.2.6.3, 2.2.6.2, 2.2.6.1, 2.2.6, 2.2.5, 2.2.4, 2.2.3.1,
2.2.3, 2.2.2, 2.2.1, 2.2.0, 2.1.4.4, 2.1.4.3, 2.1.4.2, 2.1.4.1, 2.1.4,
2.1.3, 2.1.2, 2.1.1, 2.1.0, 2.0.9.4, 2.0.9.3, 2.0.9.2, 2.0.9.1, 2.0.9,
2.0.8, 2.0.7, 2.0.6, 2.0.5, 2.0.4, 2.0.3, 2.0.2, 2.0.1, 1.6.13,
1.6.12, 1.6.11, 1.6.10, 1.6.9, 1.6.8, 1.6.7, 1.6.6, 1.6.5, 1.6.4,
1.6.3, 1.6.2, 1.6.1, 1.6.0, 1.5.5, 1.5.4, 1.5.3, 1.5.2, 1.5.1, 1.5.0,
1.4.7, 1.4.6, 1.4.5, 1.4.4, 1.4.3, 1.4.2, 1.4.1, 1.4.0, 1.3.10, 1.3.9,
1.3.8, 1.3.7, 1.3.6, 1.3.5, 1.3.4, 1.3.3, 1.3.2, 1.3.1, 1.3.0, 1.2.8,
1.2.7, 1.2.6, 1.2.5, 1.2.4, 1.2.3, 1.2.2, 1.2.1, 1.2.0, 1.1.6, 1.1.5,
1.1.4, 1.1.3, 1.1.2, 1.1.1, 1.1.0, 1.0.1, 1.0.0, 0.9.1, 0.9.0, 0.4.0,
0.3.0, 0.2.0, 0.1.0)
$ bundle add rack --version=2.2.8.1 --skip-install
$ bundle add puma sinatra net-ldap --skip-install
エラく時間を浪費させられたので憤慨する気持ちもないわけではないが、まぁ、近年のフレームワークのラクチンさは、恐ろしく多数の物件を積み上げた成果なわけで、たまにはこういうのもしゃーない。というわけで、他の人の時間の浪費が防がれることを祈って、ここに記録しておく。
というような作業の合間に引き続きドルアーガ。ついに1人を残して59階に到達。いくのか? いってしまうのか? あ゛ぁー……連続のミスで打倒ならず。まぁ、だいぶ精度は上がってきているけどなぁ。もう少しだなぁ。