2012年5月27日日曜日

HTTPメソッドとの対応

sinatraに触れると、だいたい最初の段階でCRUD操作がルーティングのpost/get/put/delete do ... endに対応する、ということを学びます。
しかしながら、多くのブラウザにはgetおよびpostの実装しかないということで、putとdeleteはもうひと工夫必要になります。
この辺りは予備知識があれば容易に分かるところですが、そうでないとなかなか辿り着くのに苦労します。
解決策としては

  • POSTによる代用
  • Javascriptによるput/deleteメソッドの生成
があります。get '/foo/delete' do ... end などとしてgetによる削除、更新処理をしている例もありますが、RESTfulなURI設計とは言い難いのでおすすめしません。
POSTによる代用は、フォームの隠しパラメータに_methodパラメータを用意しそこにメソッド名を入れます。sinatraで利用する場合は、:method_overrideを有効にすることで適切なルーティングがおこなわれます。例えば、
@@ post_delete
form method="POST"  action="/destroy_it"
  input type="hidden" name="_method" value="DELETE"
  button type="submit"
    | delete
のようなフォーム(Slim使用)あって、ボタンを押すとPOSTリクエストがサーバには届きますが、delete "/xxxx" do ... end へルーティングされます。
二番目の方法は読んでそのままですが、jQueryを使用すると下記のような形でリクエストを生成します。
$.ajax({
  type: "DELETE",
  url: "destroy_it",
  success: function(data) {
    $(".message").text(data)
  }
});
以下、両者のサンプルになります。"$ ruby app.rb"で実行できます。

app.rb

require 'sinatra/base'
require 'slim'

class MyApp < Sinatra::Base

  configure :development do
    require 'sinatra/reloader'
    register Sinatra::Reloader
  end

  configure do
    enable :inline_templates
    enable :method_override
  end

  get '/style.css' do
    scss :style
  end

  get '/post_delete' do
    slim :post_delete
  end

  get '/delete_method' do
    slim :delete_method
  end

  delete '/destroy_it' do
    content_type :text
    "delete done!!"
  end

  run! if app_file == $0
end

__END__

@@ layout
doctype html
html
  head
    title My App
    script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"
    link rel="stylesheet" href="/style.css"
  body == yield

@@ post_delete
form method="POST"  action="/destroy_it"
  input type="hidden" name="_method" value="DELETE"
  button type="submit"
    | delete

@@ delete_method
span.delete__
  | delete
div.message

javascript:
  $(function(){
    $(".delete__").click(function(){
       $.ajax({
         type: "DELETE",
         url: "destroy_it",
         success: function(data) {
           $(".message").text(data)
         }
       });
    })
  })

@@ style
span.delete__ {
  cursor: pointer;
  background-color: #dddddd;
  border: #cccccc 2px outset;
  border-radius: 5px;
  padding: 1px 4px 2px 4px;
}

div.message {
  color: red;
  margin: 2px;
  padding: 2px;
}

0 件のコメント:

コメントを投稿