simotin13's message

simotin13といいます。記事の内容でご質問やご意見がありましたらお気軽にコメントしてください\^o^/

RESTful詐欺にあった~sinatraでdeleteを送る方法~

RESTful... それはWebのスケーラビリティーを高める1つの手段。


RESTful... それはリソースに対するURIによるユニークなアドレス表現。


RESTful... それは、"GET"、"POST"、"PUT"、"DELETE"のメソッドによるリソースの操作。


かつて、Webサービスを作る際には「RESTful」という言葉がお題目のように唱えられている時代がありました。
RESTfulの考えはWebサービスの発展に大きく貢献していましたが、その高らかな宣伝とは裏腹にある事実が隠されておりました。
RESTfulの概念は、皆なんとなく理解して世の人は「いいじゃん、いいじゃん」と受け入れていたのですが、概念に従って実装しようとしたとき初めて衝撃の事実を知ったのです。

自宅ではたらく新妻の告白

Web子は28才の新妻。
独身時代は渋谷で働くWebデザイナとして活躍しており、専業主婦の傍らWebアプリケーションの開発でお小遣いを稼いでおりました。

そんなある日、

「あら、そういえばフォームとかaタグとかでPUTとDELETEってどうって送るのかしら?お隣の奥さんに、お醤油を借りるついでにきいてみなくっちゃ。」


トントントン。


Web子「あの、隣のWeb子ですけど。すいませんちょっとお醤油を切らしてしまって。少し分けて頂けると助かるのですが。」

隣の主人「ああ、いいよ奥さん。ちょっとあがってお茶でものんでいきなよ。」

Web子「こんにちわ、あら今日は奥様はいらっしゃらないんですね。じゃあちょっとだけ失礼します。あと、それからformからPUTとDELETEを送る方法ってご存知ないでしょうか?」

隣の主人「formからPUT?DELETE?クックックッ・・・奥さんも若いねぇ。ヒッヒッヒッ」

Web子「・・・」

隣の主人「まぁ上がりなよ、で?、formからPUTとDELETEを送る方法が知りたいって?」

Web子「はい、以前主人から、これからはRESTfulの時代だから、PUTとDELETEも使うようにって言われたものですから。」

隣の主人「おぉ、よく知ってんじゃねぇか。なあに簡単なことだよ。」

<form method="delete", action="/xxx">
・・・・
</form>
<form method="put", action="/xxx">
・・・・
</form>

隣の主人「こうやって書いて動かしてみなよ。奥さんにだってできそうだろ。ヘッヘッヘッ」

Web子「はい、ありがとうございます」

パチパチパチ...タンッ(言われるままにキーボード叩き、formを動かしてみるWeb子)

あら、なにこれ!?ちっとも動かないわ・・・あたし、何か間違えたのかしら

隣の主人「クックックックッ、引っかかったね奥さん。どいつもこいつもRESTfulって言葉に騙されてやってくるんだよ。」

Web子「ちょっと!何よ!?はなしてちょうだい」

隣の主人「まぁせっかく来たんだからゆっくりしていきなよ。おとなしく言うことを聞けば、formからputとdeleteを送る方法を教えてやるからよ」

Web子「・・・」



当時、メディアで拍手喝采を送られたRESTfulという概念ですが、PUTやDELETEはその中心的な存在であるにも関わらずHTMLに

<form method="put", action="/xxx">
・・・・
</form>
<form method="delete", action="/xxx">
・・・・
</form>

と書くことは許されていなかったのです。

無知なWeb子のように、このことを知らずに騙される詐欺事件が多発し、被害者達は泣き寝入りするしか方法がありませんでした。
その上、RESTfulに従う人権派の弁護士達よってメソッドオーバーライドといういかがわしい示談の方法が提唱され、詐欺事件自体うやむやにされてしまいました。

これらの詐欺事件の背景には、新興IT企業の株をマネーロンダリングに使おうとした暴力団組織がメディア通して詐欺を普及させようとしたいう思惑があったと言われています。

sinatraでdeleteやputメソッドを使う方法

ふぅ。
sinatraを使ってwebアプリを作っていて上記の話のような状態になりました。

結論から言えば、sinatraのアプリケーションクラスで、

enable :method_override

delete '/xxx/:id' do
  # 保育所落ちた。idしね。
end

のような感じで、

view側では、(HAMLのコードになりますが)

  %form{method:"post", action: "/xxx/#{@id}", name: "frm_delete"}
    %input{type: "hidden", name: "_method", value:"DELETE"}
    %input{type: "submit", value: "削除"}

のような感じで書けばformからdeleteやputメソッドは呼び出されます。

ポイントは

  • サーバ側はenable :method_overrideによりメソッドオーバーライドを有効にする
  • formに _methodでhidden属性を追加する。値は "DELETE"

の2点。

注意点として、hiddenするinputのnameは、

_method

になっている必要があるようです。
大文字で _METHOD とかすると動かないですね。

もちろんputやpatchといったメソッドも同様のやり方でvalueの値を変えてあげれば送信できます。


参考:Sinatra: Configuring Settings

なんというか、知らなかった自分が悪いのですが、formでputやdeleteが使えないのって残念を通り越して愕然としました。
雑誌とかWebの記事では、

やっぱRESTfulっしょ!お宅もWebAPI作ってるんでしょ?

みたいなノリで説明されていますけど。
そういう記事で注意事項として、

  • formではputやdeleteの呼び出しはサポートされていません
  • chromeでさえサポートされていません
  • 安心してください。Railsではサポートされていますよ。link_toの method:deleteでdelete使えたりしますよ。
  • 騙されないで、RailsではJavascriptであちこちいじくりまわしているからだよ。
  • 安心しないでください。HTML5なら使えるというのはガセネタですよ。

みたいな説明をあまり見かけないのはなぜでしょうか。
私が目をそらしているだけ!?


そもそも、RESTfulってあくまでWebAPIに特化した設計方針のことなんでしょうか。だとしたらすごく納得できるんですが。
※でもクライアント側からJavascriptでゴニョゴニョやりだすと実装が面倒くさいです。見た目とかにしてもDom操作とかしないといけなくなったりしますし。せめてformは...

というわけで、RESTfulに関しては、

formではputとかdeleteは使えへんから、気をつけんと痛い目みるで~

って、もうちょっとアピールしてくれてもいいと思いました。

ちなみにこの辺の話についてはもうだいぶ前から議論とかノウハウがあるみたいで、私もsinatraでの実装方法を調べていていくつかサイトを参考にさせて頂きました。

■参考にさせて頂いたサイト

tomiacannondale.hatenablog.com

d.hatena.ne.jp

jxck.hatenablog.com

※参考にさせて頂きありがとうございます。勉強になりました!

上記の参考にさせて頂いた記事は、結構時間のたつ記事ばかりです。
2016年の時点でこんな記事を書いていること自体情けない気もするのですが逆に言えば状況は何も変わっていないということかもしれません。

感想

とりあえずsinatraでの解決方法がみつかったのでよかった。と同時に良くも悪くもRailsの徹底っぷりに感動しました。

そもそもRESTfulの概念自体きちんと勉強しないといけないとも感じました。
オライリーからいくつか面白そうな書籍はでているのでこれを機に読んでみたいと思います。(formの件もかかれてたりするのかな。)