第5回: Ajax (2)
2012/03/15
前回に引き続き、テーマはAjaxです。
正方形をドラッグして位置を変更した場合の処理を実装します。
blocks#updateアクションの実装
Ajaxコールを受けるblocks#updateアクションを実装します。
config/routes.rb
を修正。
Toraja::Application.routes.draw do root to: "top#index" resources :blocks, only: [ :create, :update ] end
app/controllers/blocks_controller.rb
を修正。
class BlocksController < ApplicationController def create block = Block.create!(params[:block]) render text: block.id end def update block = Block.find(params[:id]) block.update_attributes!(params[:block]) render text: "OK" end end
top#indexアクションのビューを修正
app/views/top/index.html.erb
を修正。
<% @blocks.each do |block| %> <%= content_tag(:div, nil, class: "block", data: { :"block-id" => block.id }, style: "left: #{block.x}px; top: #{block.y}px") %> <% end %>
3行目に data: { :"block-id" => block.id },
を挿入しています。
この結果、div要素に data-block-id
という属性が追加され、CoffeeScript 側でBlockオブジェクトの主キー(id)の値を参照できるようになります。
Ruby 1.9で導入された { key: value }
というハッシュの記述法は、キーがシンボルで、かつキーの名前がアルファベットとアンダースコア(_)のみで構成されている場合にしか使えません。この例のように、ハイフン(-)を含むキーの場合には、伝統的な =>
を用いて記述してください。
正方形の位置を更新
現在、app/assets/javascripts/top.js.coffee
はこうなっています。
$ -> $("div#canvas").dblclick (e) -> [x, y] = positionOfNewBlock(e) $.post '/blocks', block: { x: x, y: y }, (block_id) -> block = $("<div class='block' style='left: #{x}px; top: #{y}px;' />"). draggable(containment: "parent").css(position: "absolute") $(e.target).append(block) $("div.block").draggable(containment: "parent").css(position: "absolute") positionOfNewBlock = (e) -> canvas = $(e.target) x = e.pageX - canvas.position().left y = e.pageY - canvas.position().top [x, y]
まず、5-6行目を次のように変更してください。data("blockId", block_id).
という1行を挿入しています。
block = $("<div class='block' style='left: #{x}px; top: #{y}px;' />"). data("blockId", block_id). draggable(containment: "parent").css(position: "absolute")
data("blockId", block_id)
で、生成された要素(正方形)の data-block-id
属性に値をセットしています。これがBlockオブジェクトの主キー(id)の値です。正方形の位置を変更するためのAjaxリクエストで、この値が用いられます。
属性の名前はハイフンで区切られていますが、data
メソッドに渡す名前はキャメルケースに変換する点に注意してください。
次に、9行目の $("div.block").draggable ...
の次の行に以下のコードを挿入してください。
$(document).on "dragstop", "div.block", (e) -> block = $(e.target) blockId = block.data("blockId") x = parseInt(block.css("left")) y = parseInt(block.css("top")) $.ajax "/blocks/#{blockId}", type: "PUT", data: { block: { x: x, y: y } }
では、少しずつ見ていきましょう。
$(document).on "dragstop", "div.block", (e) ->
CSSセレクタ div.block
に該当する要素で dragstop
というイベントが発生したら、->
以下のコードを実行しなさい、という意味になります。
dragstop
というイベントは標準的なイベントではなく、jQuery UIのDraggableプラグインによって提供されているものです。
on
は、jQuery 1.7で導入された比較的新しいメソッドです。要素に対してイベントハンドラを割り当ててくれます。
jQuery 1.6までは live
というメソッドでイベントハンドラの割り当てを行っていましたが、「廃止予定(deprecated)」になりました。
なお、いま自分が使っているjQueryのバージョンを調べるには、top.js.coffee
の先頭に alert $(document).jquery
を挿入して、ブラウザをリロードしてください。
block = $(e.target) blockId = block.data("blockId")
dragstop
イベントが発生した要素(正方形)の data-block-id
属性の値を変数 blockId
にセットしています。
x = parseInt(block.css("left")) y = parseInt(block.css("top"))
正方形の左上隅の位置を変数 x, y
にセットしています。css
メソッドが返す値には px
という単位が付いているので、parseInt
でメソッドで整数値に変換しています。
$.ajax "/blocks/#{blockId}", type: "PUT", data: { block: { x: x, y: y } }
正方形のidが123であるとすれば、/blocks/123
というURLにPUTメソッドでアクセスをしています。POSTメソッドでアクセスする場合とは、引数の与え方が異なるので注意してください。
修正が完了したら、動作確認をしましょう。ブラウザに戻り、ページを再読込してから、正方形をドラッグして位置を動かしてください。もう一度ページを再読込しても正方形の位置が変化しなければOKです。正方形がドラッグ前の位置に戻ってしまう場合は、Ajaxによるアクセスがうまくいっていません。ソースコードをじっくりと見直してください。
更新情報
- 「まず、5-6行目を次のように変更してください。」から「次に、」までを追加しました。(2012/3/16)
- ソースコードを修正しました。 (誤)
$("div.block").on "dragstop", (e) ->
(正)$(document).on "dragstop", "div.block", (e) ->
(2012/3/17) - 節「top#indexアクションのビューを修正」を追加しました。今回はミスが多くて、読者の皆様に大変ご迷惑をおかけいたしました。お詫びいたします。(2012/3/18)