.rjsファイルからAjaxを利用してみる。

.rjsファイルとは、RubyJavaScriptを混在して利用するためのファイル形式と勝手に思い込んでいる。(Rubyとhtmlを混在して利用するファイルは.rhtmlというファイル形式になるように。)

今までのAjaxの利用方法...

ビュー app/views/models/softwares/_edit2.rhtml
.rhtmlファイルで、更新箇所アクションを指定する。
<%= link_to_remote '選択', 
             :update => 'select_or_typing',......更新箇所
             :url => {:action => 'list_keyword'} %>......アクション
コントローラー app/controllers/softwares_controller.rb
コントローラーで、処理内容を指定する。
def list_keyword
  @text_input = false
  render :partial => "models/softwares/edit2_keyword"......処理内容
end

.rjsファイルから利用する場合...

ビュー app/views/models/softwares/_edit2.rhtml
.rhtmlファイルでは、アクションだけ指定する。
<%= link_to_remote '選択', 
             :url => {:action => 'list_keyword'} %>......アクション
コントローラー app/controllers/softwares_controller.rb
コントローラーは、list_keyword.rjsを呼び出すだけ。*1
def list_keyword
  @text_input = false
end
ビュー app/views/softwares/list_keyword.rjs
.rjsファイルで、更新箇所処理内容を指定する。
page.replace_html :select_or_typing, render(:partial => "models/softwares/edit2_keyword")......更新箇所, 処理内容

違いは?

  • 今までのAjaxの利用方法では、1回のアクションで1箇所しか、部分更新できなかった。
  • .rjsファイルを利用すれば、1回のアクションで複数箇所の部分更新が可能になる。(より複雑な処理に対応できる。)

.rjsファイルを利用してキーワード登録

それでは、実際にrjsを利用して、キーワード登録の処理を修正してみた。
現状では、キーワードを入力する場合のテキストフィールドとプルダウンリストの切り替えに、「選択|新規」の二つのリンクを表示している。さらに無駄の無いインタフェースを考えれば、テキストフィールドの時は「選択」のリンクだけ、プルダウンリストの時は「新規」のリンクだけが表示される方が良い。目標はこんな表示だ。

「新規」をクリックすると...

      • リンク表示が「選択」になる。
      • キーワードの入力フォームがテキストフィールドになる。


今まで、更新箇所が2箇所になるため実現できなかったが、rjsを利用して以下のようにやってみた。

      • 以下、オレンジ色の部分が追記したコード。緑色の部分はコードの説明。
      • 今回、変数@new_keywordを@text_inputに変更したり、id=で指定する名前を変更しているので、前回との比較が分かり難くなってしまった...。
      • 最初から分かり易く変数やメソッドなどを命名することは、とても大切なこと。
ビュー app/views/models/softwares/_edit2.rhtml
選択または新規のリンクを表示する部分を、パーシャルファイル_edit2_keyword_link.rhtmlを呼び出して表示するようにした。
...(途中省略)...
<% unless @controller.class.hidden_field?(@action_name, 'keyword_id') %>
  <tr>
    <td class="<%= localized_label_class_on(@software, 'keyword_id') %>" id='select_or_typing_label'......ビジュアルエフェクトでハイライト処理する部分
      <%= human_attribute_name(@software, 'keyword_id') %>
      <sub id="select_or_typing_link">......選択、または新規のリンクを表示する部分
        <%= render :partial=>"models/softwares/edit2_keyword_link" %>          
      </sub>
    </td>
    <td id="select_or_typing">......プルダウンリスト、またはテキストフィールドを表示する部分
      <%= render :partial=>"models/softwares/edit2_keyword" %>
    </td>
  </tr>
<% end %>
ビュー app/views/models/softwares/_edit2_keyword_link.rhtml
上記で呼び出されて、選択または新規のリンクを描画するパーシャルファイル。ファイルを新規追加した。
<% if @text_input %>
  <%= link_to_remote '選択', 
                     :url => {:action => 'change_keyword_form', :text_input => false} %>
<% else %>
  <%= link_to_remote '新規', 
                     :url => {:action => 'change_keyword_form', :text_input => true} %>
<% end %>
  • パラメーター:text_inputをセットして、change_keyword_formメソッドを呼び出す。
ビュー app/views/models/softwares/_edit2_keyword.rhtml
キーワードの入力フォームを描画する。変更なし。
<% if @text_input %>
  <%= text_field :keyword, :name, :size => 60 %>
<% else %>
  <%= collection_select :software, :keyword_id, Keyword.find_all, :id, :name, :include_blank => false, :prompt => '選択してください。' %>
<% end %>
コントローラー app/controllers/softwares_controller.rb
new_keyword、list_keywordメソッドを一つにまとめて、change_keyword_formメソッドにした。
...(途中省略)...
protected
  def create_keyword
    if params[:keyword]
      @keyword = Keyword.find(:first, :conditions => ["name LIKE ?", params[:keyword][:name]])
      if @keyword == nil        
        form = Software.new(params[:software])
        form.keyword_id = 1
        
        @text_input = true
        @keyword = Keyword.new(params[:keyword])
        @keyword.save if form.valid? || !@keyword.valid?
      end
      params[:software][:keyword_id] = @keyword.id || @keyword.name
    end
  end
...(途中省略)...
  def change_keyword_form
    @text_input = params[:text_input]......パラメーターをインスタンス変数にセットして、change_keyword_form.rjsを実行する。
  end
...(途中省略)...
ビュー app/views/softwares/change_keyword_form.rjs
ファイルを新規追加した。
page.replace_html :select_or_typing_link, render(:partial => "models/softwares/edit2_keyword_label")
page.replace_html :select_or_typing, render(:partial => "models/softwares/edit2_keyword")

page.visual_effect :highlight, 'select_or_typing_label'
page.visual_effect :highlight, 'select_or_typing'
  • 選択または新規のリンクと、キーワード入力のフォームを部分更新して、ビジュアルエフェクトのハイライト処理をする。
  • pageは、ブラウザが表示している処理対象のページのオブジェクトを示す。
  • 「page . 処理するJavaScriptの指定 オプション指定」の書式でコーディングする。

参考リンク

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

*1:コントローラーでrenderを指定しない場合、デフォルトでメソッド名と同じlist_keyword.rjsを呼び出す。(もし、list_keyword.rhtmlが存在すれば、それが優先される。)