ObtrusiveだったUnobtrusive JavaScript

DeviseとPaperclipを使ったUserモデルができつつあるのはいいけど、Userをdevise/registrations#destroyしようとしても、どうもアカウントが消せない。標準で、

rails g devise:view

として吐き出したビューのeditには、

%h3 Cancel my account
%p
  Unhappy? #{link_to "Cancel my account", registration_path(resource_name), :confirm => "Are you sure?", :method => :delete}.
  
= link_to "Back", :back

と、アカウントを消去するリンクがあるのだけど、これが機能していない。なぜか/usersにリダイレクトされるだけ。

変だなぁと思って、rake routesでルーティングを調べてみた。すでにUser#showなどには:idではなく、:usernameを使うようにroutes.rbを書き換えているので、何かおかしいのだろうと思った。ところが、

user_registration DELETE /users(.:format)               {:action=>"destroy", :controller=>"devise/registrations"}

と、ちゃんとdestroyアクションに紐づいている。

で、ログを見てみたら、

Started GET "/users" for 127.0.0.1 at 2010-10-23 13:56:16 +0900

ActionController::RoutingError (No route matches "/users"):

とかなってる。あれ、GETってなんでだ? DELETEメソッドで叩いてくれないと困るやんか……。と、ここまで来て気付いた。吐き出されるHTMLを見てみると、

<h3>Cancel my account</h3> 
  <p> 
  Unhappy? <a href="/users" data-confirm="Are you sure?" data-method="delete" rel="nofollow">Cancel my account</a>.
  </p> 

となっている。「data-method=」でメソッド名を渡してる! そうか、これが噂のunobstrusiveなJavaScriptかと思って、改めてHTMLを見てみたら、JavaScriptを1つもインクルードしていないじゃん……。アウチ。

結局、正解は、Rails2.3系から持ってきたレイアウトファイルに、

<%= javascript_include_tag :defaults %>

とか、HAMLだったら、

= javascript_include_tag :defaults

などと書くことだった。これでHTMLには、

</title> 
<link href='/favicon.ico' rel='shortcut icon'> 
<meta content='text/html; charset=utf-8' http-equiv='Content-Type'> 
<link href="/stylesheets/application.css?1287696458" media="screen" rel="stylesheet" type="text/css" /> 
<script src="/javascripts/prototype.js?1287624812" type="text/javascript"></script> 
<script src="/javascripts/effects.js?1287624812" type="text/javascript"></script> 
<script src="/javascripts/dragdrop.js?1287624812" type="text/javascript"></script> 
<script src="/javascripts/controls.js?1287624812" type="text/javascript"></script> 
<script src="/javascripts/rails.js?1287624812" type="text/javascript"></script> 
<script src="/javascripts/application.js?1287624812" type="text/javascript"></script> 

と書き出されるようになる。このうち、rails.jsこそが、aタグの属性をよしなに書き換えてくれるスクリプトの本体ということだった。

参考:Unobtrusive JavaScript in Rails 3


よく分からないけど、今さらprototype.jsってないんじゃないの、jquery.jsにしといたほうがいいよねと思ったら、ここに、やり方が書いてあった。

module ActionView::Helpers::AssetTagHelper
  remove_const :JAVASCRIPT_DEFAULT_SOURCES
  JAVASCRIPT_DEFAULT_SOURCES = %w(jquery.js rails.js)

  reset_javascript_include_default
end

というのを、config/initializers以下においておけばいいらしい。そうかぁ、いきなりremove_constとかやっちゃうのかぁ、なるほどなー。