in_place_editorを使ってみる。

今の状態では、CSVリストをフィルターで絞り込み、属性変更の編集ページに移動して、再びCSVリストページに戻ってきた時に、フィルターは解除されてしまう。もう一度同じCSVファイルを見つけるのにフィルターを再設定する必要があり、フィルター条件が複雑だったりすると手間がかかる。そこで考えたのが、ページを切り替えるまでもなく、同じページで修正してajax更新すれば良いのではないかということ。(属性の変更可能な項目はコメント、編集可能フラグ、管理部門のたった3項目だけなので。)
それを実現する方法を調べてみると、Railsでは、in_place_editorをとてもシンプルに利用できるヘルパメソッドが存在する。in_place_editorを使えば、編集したい文字列をクリックすると、その部分だけが入力フォームに変化して、その場で編集することが可能になる。初めて体験した時は、なんだかとても斬新な機能に感じた。早速、CSVサーバーにも取り入れてみた。

基本パターン

app/views/csvs/_listd.rhtml
ビュー
  • ビューでは、text_fieldと同じ書式で以下のようにすればOK。すでにlistdにはCSVモデルの1レコードが代入されているが、..._field :csv, :file_commentの書式に合わせるため、@csv = listdでルール上必要と思われる変数に代入した。(なんか無駄なことをしている気がするが、良いやり方が他にあるのだろうか?)
...(途中省略)...
<%#=h listd.file_comment %>
<%# リスト表示の上記コードを以下のように変更した。 %>
<% @csv = listd %>
<%= in_place_editor_field :csv, :file_comment %>
...(途中省略)...
app/controllers/csvs_controller.rb
コントローラー
  • コントローラーに以下のように指定すると、in_place_editor_fieldからのパラメータを受け取り、データベースの更新とビューの描画を適切に処理してくれる。
class CsvsController < ApplicationController
  in_place_edit_for :csv, :file_comment
...(途中省略)...
      • 上記のように宣言することは、以下のメソッドを定義することと同等である。
      • :idには修正したレコードのid、params[:value]には入力した値が代入されている。
  def set_csv_file_comment
    @item = Csv.find(params[:id])
    @item.update_attribute('file_comment', params[:value])
    render :text => @item.send('file_comment')
  end

以上のコードだけで、今までのコメント部分が直接編集可能な状態になる。素晴らしくシンプルな書き方だ。ところが、1つ問題が発生。文字が入力されていないと編集モードに移行できない...。

ブランク項目で編集モードに移行する方法

いろいろな回避方法があるようだが、ここでは以下のようにやってみた。

  • コメントの先頭には常に「»」マークを表示する。
  • :external_controlオプションで、上記マークのid属性を指定する。
  • これで上記マークをクリックすれば、ブランク項目であっても編集モードに移行することが可能になる。
<span class="empty_message" id="file_comment<%= listd.id %>">&#187;</span>
<%= in_place_editor_field :csv, :file_comment, {}, :external_control => "file_comment#{listd.id}" %>

CSVサーバーに合わせた調整

その他にもこのような欲求があったので、結局、全部まとめて以下のようになった。

  • 「ok」「cancel」ボタンを日本語で表示したい。
  • 入力値のサニタイズが必要なのではないか?
  • 同じ管理部門のユーザーしか編集できないように制限したい。
  • 編集中はテキストエリアを表示したい。(テキストフィールドではカーソルの位置が確認できない表示だったので。)
    • :rowsが1ならテキストフィールド
    • :rowsが2以上ならテキストエリア
...(途中省略)...
  <td <%= arranged_class("file_comment") %>>
      <% listd.file_comment = sanitize(listd.file_comment) %>
      <% if management_section?(listd.management_section) %>
        <span class="empty_message" id="file_comment<%= listd.id %>"><%= "&#187;" %></span>
        <%= in_place_editor_field :csv, :file_comment, {}, 
                                  :rows => 2, :save_text=>"保存", :cancel_text=>"キャンセル", 
                                  :external_control => "file_comment#{listd.id}" %>
      <% else %>
        <%=h listd.file_comment %>
      <% end %></td>
...(途中省略)...

参考ページ

以下のページが大変参考になりました。感謝です。


しかし、まだまだ使いこなすためには理解を深める必要がある...。簡単そうだけど、自由に使いこなすには知識が必要だ。