Ajaxでキーワード登録の使い勝手の向上を目指す。

id=keyword_nameのダブりに気付くまでに、ずいぶん遠回りをしてしまった...。しかし、試行錯誤の中でいろいろなことを試すことが出来たので、今まで知らなかったことも新たに発見することができた。新たな知識を活用して、もう少しキーワード追加の処理方法やインターフェースを改善してみることにする。

テキストフィールドに登録済のキーワードを入力した時の動作

現状では、同じキーワードが登録済の場合は、モデルkeyword.rbのバリデーションによって、エラーになる。でも、ユーザーの立場で考えれば、エラーにしないで登録済のキーワードを選択して、ソフトウェアブックへの登録処理を進めて欲しいと思うはず。テキストフィールドで新規追加しか処理していないから問題なのだ。条件によっては、プルダウンリストのようにキーワードを選択する処理も追加してみる。

app/controllers/softwares_controller.rb 修正1
protected
  def create_keyword
    if params[:keyword]
      @keyword = Keyword.find(:first, :conditions => ["name = ?", params[:keyword][:name]])
      if @keyword == nil......同じキーワードが存在しない時だけ新規追加する
        @new_keyword = true
        @keyword = Keyword.new(params[:keyword])
        @keyword.save
      end
      params[:software][:keyword_id] = @keyword.id
    end
  end


上記では、「rails」と「Rails」が違うキーワードとして判断されて新規追加されてしまう。大文字と小文字が違っていても、スペルが同じなら、新規追加ではなく選択するようにしたい。

app/controllers/softwares_controller.rb 修正2
protected
  def create_keyword
    if params[:keyword]
      @keyword = Keyword.find(:first, :conditions => ["name LIKE ?", params[:keyword][:name]])
...(以下省略)...

「=」を「LIKE」に置き換えるだけで大文字と小文字の区別はなくなった。ちなみに、以下のような書き方があるようだ。

["name = ?", params[:keyword][:name] 大文字と小文字の区別あり、完全一致
["name LIKE ?", params[:keyword][:name] 大文字と小文字の区別なし、完全一致
["name LIKE ?", params[:keyword][:name] + '%'] 大文字と小文字の区別なし、前方一致
      • %の置き場所によって、後方一致や部分一致にも出来る。SQLについてもっと勉強すればさらに理解が深まるはずなのだが...。


まだ問題がある。入力検証エラーが発生しても、キーワードだけ新規追加されてしまう可能性がある。フォームの作成や確認のボタンを押して、エラーが無い時だけ追加するようにしないと、ユーザーが混乱する。そこで以下のようにした。

app/controllers/softwares_controller.rb 修正3
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......仮にkeyword_idを設定する。
        
        @new_keyword = true
        @keyword = Keyword.new(params[:keyword])
        @keyword.save if form.valid?......エラーが無ければキーワードを新規追加する。
      end
      params[:software][:keyword_id] = @keyword.id
    end
  end


さらに修正。テキストフィールドにキーワードが未入力の時、エラー表示するため。softwaresテーブルとkeywordsテーブル、両方のエラーを調和させることは結構難しい...。(もっと分かり易い書き方ってあるのだろうか...。)

app/controllers/softwares_controller.rb 修正4
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......仮にkeyword_idを設定する。
        
        @new_keyword = true
        @keyword = Keyword.new(params[:keyword])
        @keyword.save if form.valid? || !@keyword.valid?......1) ソフトウェアにエラーが無ければキーワードを新規追加する。またはキーワードにエラーがあればその表示のために保存処理を行う。
      end
      params[:software][:keyword_id] = @keyword.id || @keyword.name......2)
    end
  end
  1. キーワードにエラーがあれば、エラー表示のために保存処理をする。
  2. keyword.idが存在しなければ、一時的に@keyword.nameを代入して、エラー表示を正常に行う。

プルダウンリストの初期表示。

現状では、ソフトウェアの新規追加をする時、プルダウンリストの初期表示はキーワードの一つ目の値になっている。これだとユーザーが選択するのを忘れても、初期表示のキーワードのまま登録されてしまう。初期表示はキーワードと関係ない値にして、操作しないまま登録した時はエラーになるようにしたい。

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, :prompt => '選択してください。' %>
<% end %>

オプションを一つ追加するだけでOK。ちなみに:include_blank => trueを設定すれば、空白行が追加される。

ビジュアルエフェクトを使ってみる。

特に必要性はないが、いろいろ調べているうちにこんな演出も出来ることを知った。手軽なので、忘れないように使ってみた。これもオプション設定を追加するだけでOK。

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 => 'select_or_typing',  
             :url => {:action => 'list_keyword'}, 
             :complete => visual_effect(:highlight, 'select_or_typing', :duration => 1) %> |
    <%= link_to_remote '新規', 
             :update => 'select_or_typing', 
             :url => {:action => 'new_keyword'}, 
             :complete => visual_effect(:highlight, 'select_or_typing', :duration => 1) %>
    </sub>

これで、プルダウンリストとテキストフィールドを切り替えた時に一瞬セルがフラッシュするようになる。ビジュアルエフェクトって楽しい!手軽に使えるところもいい!

:complete => link_to_remoteの部分更新が完了した時に行う処理
 visual_effect( ビジュアルエフェクトを呼び出し
  :highlight, ハイライト処理を指定
  'select_or_typing', ハイライト処理の場所を指定
  :duration => 1) ハイライト処理の時間を1秒に指定(指定しないとデフォルト時間になる)
      • :highlightの他に、左右に揺れる:shakeなんてのもある。その他にもいろいろなエフェクトがあるようだ。詳しくはRDocのマニュアル参照。

スタイルシートの調整

エラー表示についても今までSafariで確認していたので気付かなかったが、Firefoxで確認すると、見栄えが悪い。
Firefox:

エラーが発生しても、フォームの周りがほとんど赤くならない。スタイルシートを調整してみた。

public/stylesheets/scaffold.cssの修正
...(途中省略)...

form td.labelWithErrors{ /*......form の追加*/
  background-color: pink;
  vertical-align: top;
}
...(途中省略)...

.fieldWithErrors {
  padding: 2px;
  background-color: red;
  display: table;
  outline-style: solid; /*......追加*/
  outline-width: 2px;   /*......追加*/
  outline-color: red;   /*......追加*/
}
...(途中省略)...
  • エラーの時、フィールド名のセルが、ピンク色になる。
  • Firefoxは、フォーム部品の余白がほとんど無いので、強制的に赤枠で囲う。

これで、以下のように表示されるようになる。
Firefox:

Safari:


これでキーワードの追加処理については、ほぼ満足。