プルダウンリストでキーワードの絞り込み

現状のキーワードを絞り込む操作は、絞り込みたいキーワードのリンクをクリックする。もう一度クリックすると、絞り込み解除。しかしこれだと、現在のページに表示されていないキーワードで絞り込みたい時に困ってしまう。操作環境としては、プルダウンリストが表示されていて、そこから選択したキーワードに絞り込まれる方がいい。

プルダウンリストの取り扱い

プルダウンリストは、編集や新規作成のページで既に利用(app/views/models/softwares/_edit2_keyword.rhtml)しているので、同じ仕組みで簡単に実現できるとやってみが...

collection_select

同じメソッドcollection_selectを利用すると、選択済みのキーワードを、Softwareモデルのkeyword_idとして、インスタンスごと保存しないとうまくいかない...。

# コントローラー
@software = Software.new(:keyword_id => 1)
<%# ビュー %>
<%= collection_select :software, :keyword_id, 
                      Keyword.find_all, 
                      :id, :name, 
                      :include_blank => true %>
  • 単なるIDという数値を扱いたいだけなのに、これだと無駄が多い。
  • それにキーワードのリンクをクリックして絞り込む操作も残したいので、工夫しないとうまく連携できない。
select

selectメソッドには、:selectedというオプションがある。以下のようにすれば、Softwareモデルとは無関係に、数値だけを扱うことができそうだ。

# コントローラー
@keyword_id = 1
<%# ビュー %>
<%= select :software, :keyword_id, 
           Keyword.find_all.collect {|p| [ p.name, p.id ] }, 
           :selected => @keyword_id, 
           :include_blank => true %>

キーワードの絞り込みには、selectメソッドを利用することに決定。

      • collection_selectでも、:selectedや:selected_valueでオプション設定してみたが、指定した値を選択してくれない...。

値を監視して、変化したら絞り込む

キーワードのプルダウンリストは表示されるようになったが、キーワードを選択しても、何も起こらない...。それはフォームの送信をしていないからだ。フォームの送信のためには「絞り込み」ボタンを作ればいいのだが、その都度ボタンを押すのは面倒だ。選択したキーワードで自動的に絞り込むようにしたい。Railsが用意してくれたメソッド、observe_fieldを使ってみた。

<%= select :software, :keyword_id, 
           Keyword.find_all.collect {|p| [ p.name, p.id ] }, 
           :selected => @keyword_id.to_i, 
           :include_blank => true %>

<%= observe_field :software_keyword_id, 
                  :update => "list_update", 
                  :submit => "store", 
                  :url => {:action => 'list_update'} %>

上記のようにしておくと、:software_keyword_idという場所を監視して、値が変化したら...

  • :url=>で指定するメソッドを呼び出す。
  • :submit=>で指定するフォームを送信する。
  • :update=>で指定する場所を更新する。
      • すべてhtmlのid属性で指定する。(例:<div id="list_update"><)/span>
      • <%= select :software, :keyword_id, ...%>のように指定すると、id属性はsoftware_keyword_idになる。

実際のコード

app/views/models/softwares/_list_form.rhtml
  • キーワードのプルダウンリストの位置を、キーワード列と合わせたいため、テーブル表示にした。
  • プルダウンリストが値を保持するので、キーワードのhidden_fieldは削除した。
  • 条件をリセットするリンクは、ページの下に「新規作成 | リセット」のように表示するようにした。
<%# ----ファイル名 app/views/models/softwares/_list_form.rhtml------ %>
<div id="store">
  <%= form_remote_tag :update => "list_update", 
                      :submit => "store", 
                      :url => {:action => 'list_update'} %>
  <table width=100%><tr>
  <td width=70%>
    <span style="font-weight:bold;">
    <%= human_attribute_name(Software, "title") %>/<%= human_attribute_name(Software, "description") %>
    </span>を検索 :
    <%= text_field_tag("store_search_word", @search_word) %>    
    <%= submit_to_remote "store", "検索", 
            :update => "list_update", 
            :submit => "store", 
            :url => {:action => 'list_update'} %>
    <small>
    <%= link_to_remote "クリア", 
            :update => "list_update", 
            :submit => "store", 
            :url => {:action => 'list_update', :store_search_word => ""} %>
    </small>
  </td>

  <td width=16%>
    <%= select :software, :keyword_id, 
            Keyword.find_all.collect {|p| [ p.name, p.id ] }, 
            :selected => @keyword_id.to_i, 
            :include_blank => true %>
    <%= observe_field :software_keyword_id, 
            :update => "list_update", 
            :submit => "store", 
            :url => {:action => 'list_update'} %>
    <%= hidden_field_tag("store_order_field", @order_field) %>
    <%= hidden_field_tag("store_order_direction", @order_direction) %>
    <%#= hidden_field_tag("store_keyword", @keyword_id) %><%# <---削除、selectに置き換えた %>
  </td>

  <td>
  </td>
  </tr></table>
  <%= end_form_tag %>
</div>
app/controllers/softwares_controller.rb
  • プルダウンリストからのパラメーターを受け取るために、params[:software] && params[:software][:keyword_id]のように取得した。params[:software][:keyword_id]だけでは、listアクションで、nil[:keyword_id]のハッシュ値を求めてエラーになってしまった。
  • paramsで取得する値は、文字列になってしまうようだ。@keyword_idはselectメソッドで利用するとき、selected=>@keyword_id.to_iのように変換する必要がある。
# ----ファイル名:app/controllers/softwares_controller.rb------
...(途中省略)...
  def set_pagination
   #パラメーターを取得
    ###以下変更
    #@keyword_id = params[:keyword] || params[:store_keyword] || "%"
    @keyword_id = params[:keyword] || (params[:software] && params[:software][:keyword_id]) || "%"

    @order_field = params[:order_field] || params[:store_order_field] || "id"
    @order_direction = params[:order_direction] || params[:store_order_direction] || "ASC"
    @search_word = params[:store_search_word]
    
   #条件によって、パラメーターを変更
    ###以下変更
    #@keyword_id = "%" if params[:keyword] == params[:store_keyword]
    @keyword_id = "%" if params[:keyword] == (params[:software] && params[:software][:keyword_id])

    ###1行追加
    @keyword_id = "%" if @keyword_id.to_i < 1

    @order_direction = 'ASC' if params[:order_field] && !(params[:order_field] == params[:store_order_field])
    @direction_mark = @order_direction == 'DESC' ? '' : ''
    @order_next_direction = @order_direction == 'DESC' ? 'ASC' : 'DESC'
    
   #paginate処理
    conditions = ["keyword_id LIKE ? AND (title LIKE ? OR description LIKE ?)", 
                  @keyword_id ,"%#{@search_word}%" ,"%#{@search_word}%" ]
    order = "#{@order_field} #{@order_direction}"
    @software_pages, @softwares = paginate :softwares, :per_page => 2,
                                           :conditions => conditions,
                                           :order => order
  end

  def list_update
  Software.with_scope(login_user) do
    @ajax_update = true
    set_pagination
    render :action => "list", :layout => false
  end
  end
...(途中省略)...

これで、プルダウンリストでキーワードを選択しただけで、絞り込んでくれる。今までのキーワードのリンクをクリックする操作もそのまま使える。現在の見た目はこんな感じ...。