コードでもカナでも漢字でも検索可能なプルダウンリスト

銀行と支店が連動して、だいぶ使い易くなってきたが、まだまだストレスを感じる。今、検索のキーになっているのはkanaフィールドのみ。ユーザーの中には、よく使う銀行コードは覚えてしまっているからコードで指定したいんだとか、正しい読み方は分からないけど漢字なら知っているというケースもあるだろう。
だからといって、code、kana、name用のtext_fieldを3つ用意するなんていう使い勝手を無視したインターフェースにはしたくない。入力するtext_fieldは一つ、コードでもカナでも漢字でも区別なく検索できることを目指す。

コントローラーの修正

  • 検索するのはコントローラーなので、まずは以下のように修正した。
# コントローラー:銀行の検索
def auto_complete_for_bank_kana
  @phrase = params[:bank][:kana].gsub(/[ ]/,' ').strip.downcase
  find_options = { 
    :conditions => ["(LOWER(id) LIKE ? OR LOWER(kana) LIKE ? OR LOWER(name) LIKE ?)",
                    "#{@phrase.gsub(/^0+/, '')}", "%#{@phrase}%", "%#{@phrase}%"],
    :order => "kana ASC",
    :limit => 10 }
  @items = Bank.find(:all, find_options)
  render :partial => 'auto_complete_for_bank_kana'
end

# コントローラー:支店の検索
def auto_complete_for_branch_kana
  @phrase = params[:branch][:kana].gsub(/[ ]/,' ').strip.downcase
  Branch.with_scope(:find=>{:conditions=>[ "bank_id=?", params[:payee_account][:bank_id] ]}) do
    find_options = { 
      :conditions => ["(LOWER(code) LIKE ? OR LOWER(kana) LIKE ? OR LOWER(name) LIKE ?)",
                      "#{@phrase.gsub(/^0+/, '')}", "%#{@phrase}%", "%#{@phrase}%"],
      :order => "kana ASC",
      :limit => 10 }
    @items = Branch.find(:all, find_options)
    render :partial => 'auto_complete_for_branch_kana'
  end
end
  • 余分なスペースを削除して、検索キーを@phraseに代入しておく。
  • 上記キーを元に、:conditionsの部分でフィールドごとの条件を書いてORで繋げた。
  • コード検索については「0009」も「9」も同じコードと見做すことにした。("#{@phrase.gsub(/^0+/, '')}")

選択リストのビューを修正

複合的な検索は、上記コントローラーの修正だけで実現できているが、選択リストの見た目にも少し手を加えてみた。

<%# ビュー_auto_complete_for_bank_kana.rhtml %>
<ul>
  <% @items.each do |item| %>
    <li>
      <%# 支店情報をクリアするための項目 %>
      <span connect="payee_account_branch_id"></span>
      <span connect="branch_kana"></span>

      <%# 値を設定するための非表示項目 %>
      <span connect="payee_account_bank_id" style="display:none"><%= item.id %></span>
      <span connect="bank_kana" style="display:none"><%= fit_digit(item.id, 4) %> <%= item.name %></span>

      <%# 選択リストに表示する項目 %>
      <span class="informal" style="margin:2.8em"><%= highlight(item.kana, @phrase) %><br /></span>
      <span class="informal"><%= fit_digit(item.id, 4) %> <%= highlight(item.name, @phrase) %></span>
    </li>
  <% end %>

  <% if @items.blank? %>
    <li>
      <span connect="payee_account_branch_id"></span>
      <span connect="branch_kana"></span>

      <span connect="payee_account_bank_id"></span>
      <span connect="bank_kana"></span>
      <span class="informal">銀行が見つかりません。</span>
    </li>
  <% end %>
</ul>
  • リストを選択すると、「0001 みずほ銀行」のように表示されるようにした。
  • 検索キーと一致したら、カナ、漢字それぞれを強調表示(ハイライト)するようにした。
  • 本来は以下のようにしたかったのだが、highlightを使うとその部分がtext_fieldに表示されなかった(謎)ので、仕方なく「値を設定するための非表示項目」と「選択リストに表示する項目」に分けて描画することにした。
<span connect="bank_kana"><%= fit_digit(item.id, 4) %> <%= highlight(item.name, @phrase) %></span>
  • 漢字の銀行名の上にカナ表示するようにしてみた。
  • fit_digitは、自分で定義した、数値の桁数を揃えるヘルパメソッド。
# ---------- app/helpers/application_helper.rb ----------
module ApplicationHelper
  # 数値の桁数を揃えた文字列を返す。
  # fit_digit(数値, 桁数, 不足する桁を埋める文字)
  # 例:
  # fit_digit(1, 4) => "0001"
  # fit_digit(12, 4, '_') => "__12"
  def fit_digit(value, digit, str='0')
    str * (digit - value.to_s.size) + value.to_s rescue value.to_s
  end

同じように支店のリスト表示も修正する。

<%# ビュー_auto_complete_for_branch_kana.rhtml %>
<ul>
  <% @items.each do |item| %>
    <li>
      <%# 値を設定するための非表示項目 %>
      <span connect="payee_account_branch_id" style="display:none"><%= item.id %></span>
      <span connect="branch_kana" style="display:none"><%= fit_digit(item.code, 3) %> <%= item.name %></span>

      <%# 選択リストに表示する項目 %>
      <span class="informal" style="margin:2.3em"><%= highlight(item.kana, @phrase) %><br /></span>
      <span class="informal"><%= fit_digit(item.code, 3) %> <%= highlight(item.name, @phrase) %></span>
    </li>
  <% end %>

  <% if params[:payee_account][:bank_id].blank? %>
    <li>
      <span connect="payee_account_branch_id"></span>
      <span connect="branch_kana"></span>
      <span class="informal">銀行を先に入力してください。</span>
    </li>
  <% elsif @items.blank? %>
    <li>
      <span connect="payee_account_branch_id"></span>
      <span connect="branch_kana"></span>
      <span class="informal">支店が見つかりません。</span>
    </li>
  <% end %>
</ul>

これで、現在の見た目はこんな感じ。