もう少しちゃんとAjaxでキーワードを新規登録。

キーワードが手軽に登録できるようになったと喜んでいたのも束の間、すぐに問題が発覚。その解決に時間を取られてしまった。
まず、いつも動作確認はSafariでしているのだが、その後たまたまFirefoxで操作してみたら、プルダウンリストからテキストフィールドに切り替わらない...。Ajaxなんて初めて使うので、こんな時、どこに問題があるのか見当もつかなかった。仕方なく実験用にもう一つプロジェクトを作成して、同じようなAjax処理を試してみると、こちらはちゃんと動く...。なぜなんだ...と、さらに悩みは深くなるのだが、動いたコードをそのままsoftwarebookにコピーしてみると、今度は動いた。試行錯誤の結果、原因と思われることは以下の部分。

keyword_nameがダブっていた!

app/views/models/softwares/_edit2.rhtml 正常に動作しないコード

...(途中省略)...
      <% unless @controller.class.hidden_field?(@action_name, 'keyword_id') %>
      <tr>
        <td class="<%= localized_label_class_on(@software, 'keyword_id') %>">
          <%= human_attribute_name(@software, 'keyword_id') %>
          <sub>
          <%= link_to_remote '選択', 
                   :update => 'keyword_name', ......一部更新するブロックを指定
                   :url => {:action => 'list_keyword'} %> |......そのとき呼び出すアクションを指定
          <%= link_to_remote '新規', 
                   :update => 'keyword_name', ......一部更新するブロックを指定
                   :url => {:action => 'new_keyword'} %>......そのとき呼び出すアクションを指定
          </sub>
        </td>
        <td>
        <span id="keyword_name">
          <%= render :partial=>"models/softwares/edit2_new_keyword" %>......この部分だけ更新される
        </span>
        </td>
      </tr>
      <% end %>
</table>
<!--[:]-->
  • Ajaxでupdate => keyword_nameで指定した部分更新する場所を指定するid
  • text_fieldで指定したtext_field :keyword, :nameが生成するid

どちらもkeyword_nameでダブっているためFirefoxでは正常に動作しなくなっていたのだ...。

app/views/models/softwares/_edit2_new_keyword.rhtml

<% if @new_keyword %>
  <%= text_field :keyword, :name, :size => 60 %>
<% else %>
  <%= collection_select :software, :keyword_id, Keyword.find(:all), :id, :name %>
<% end %>

app/views/models/softwares/_edit2.rhtml 修正後のコード

  • Ajaxで部分更新する場所のidをselect_or_typingに変更した。
  • ついでに、わざわざ<span>で囲ってidを指定する必要もないので、<td id="select_or_typing">で指定することにした。
...(途中省略)...
      <% unless @controller.class.hidden_field?(@action_name, 'keyword_id') %>
      <tr>
        <td class="<%= localized_label_class_on(@software, 'keyword_id') %>">
          <%= human_attribute_name(@software, 'keyword_id') %>
          <sub>
          <%= link_to_remote '選択', 
                   :update => 'select_or_typing', ......一部更新するブロックを指定
                   :url => {:action => 'list_keyword'} %> |......そのとき呼び出すアクションを指定
          <%= link_to_remote '新規', 
                   :update => 'select_or_typing', ......一部更新するブロックを指定
                   :url => {:action => 'new_keyword'} %>......そのとき呼び出すアクションを指定
          </sub>
        </td>
        <td id="select_or_typing">......<span>は削除して、tdの中で部分更新の場所を指定した
          <%= render :partial=>"models/softwares/edit2_new_keyword" %>......この部分だけ更新される
        </td>
      </tr>
      <% end %>
</table>
<!--[:]-->

これでFirefoxでもちゃんと動くようになった!

教訓

命名のダブりに気を付ける。特にRailsでは規約による命名規則に従って、自動的に変数やidが生成されている。ダブってしまうと不具合の原因になる。(それにしても何でSafariでは正常に動いてしまったんだろう?)