複数のフィルターでさらに絞り込みたい!その2
フィルター条件に行番号情報を付加する。
paramsの挙動が理解できたところで、フィルター条件に行番号情報を付加してみる。まず、現在フィルター条件が何行あるかという情報を保持しておく必要があると考えた。ここでは余計な手間をかけたくないので、セッションを利用することにした。session[:filter_count]を準備して、そこで保持することにする。そうするとコントローラーのlist、add_filterアクションは以下のようになる。
- app/controllers/csvs_controller.rb
- コントローラー
- listアクションは最初にページを読み込んだ時だけ実行される。session[:filter_count] = 0で、初期化する。
- add_filterアクションの時は、session[:filter_count] += 1で、カウントを1つ増やす。
- set_paginationの:conditionsの設定で、複数条件を組み合わせたSQLを取得している。
class CsvsController < ApplicationController ...(途中省略)... def list # 配列の設定 @date_input_sample = '<span id="date_input_sample">(入力例: 2007/4/1 , 4/1 , 6:10)</span>' @column_titles = %w{file_name file_comment editable file_size created_at file_updated_at management_section_id user_id} session[:filter_count] = 0 @filter_column = @column_titles[0] set_pagination render :action => 'list' end def add_filter # 配列の設定 @date_input_sample = '<span id="date_input_sample">(入力例: 2007/4/1 , 4/1 , 6:10)</span>' @column_titles = %w{file_name file_comment editable file_size created_at file_updated_at management_section_id user_id} session[:filter_count] += 1 @filter_column = @column_titles[0] render :partial => 'list_filter_condition' end # paginateを設定するメソッド別に作成して、作業を分担した。 def set_pagination # :conditionsの設定 filter = params[:filter] || {"0"=>{:column=>@column_titles[0], :item=>"", :id=>20}} sqls = [] filter.each {|c, f| sqls << Filtersql.human_compair_sql(f[:column], f[:item], f[:id])} @conditions = sqls.join('AND') # :orderの設定 sort_field = params[:sort_field] || 'id' sort_field = 'id' if sort_field.empty? @next_direction = (params[:sort_direction] == 'asc') ? 'desc' : 'asc' @order = "#{sort_field} #{@next_direction}" @csv_pages, @csvs = paginate :csvs, :per_page => 10, :conditions => @conditions, :order => @order end ...(途中省略)...
- app/views/csvs/_list_filter_condition.rhtml
- ビュー(「ファイルが...を含む」等の条件の入力フォームを描画)
- パラメーターを送信するフォーム全てに、以下の設定を追記した。
- "filter_#{session[:filter_count]}_column"
- :name => "filter[#{session[:filter_count]}][column]"
<li> <%# フィルタ列の選択 %> <% options = @column_titles.map{|t| [Csv.human_attribute_name(t), t]} %> <%= select_tag "filter_#{session[:filter_count]}_column", options_for_select(options, @filter_column), :name => "filter[#{session[:filter_count]}][column]" %>が <%# フィルタ列を選択するselect_tag :filter_columnを監視して、変化したら、再描画する。 %> <%= observe_field "filter_#{session[:filter_count]}_column", :update => "filter_update", :submit => "filter_params", :url => {:action => 'change_filter_column'} %> <%# フィルタ文字と比較方法を入力 %> <%# 列タイトルごとに部分テンプレートを用意 _filter_フィールド名.rhtml %> <%= render :partial => "filter_#{@filter_column}" %> </li>
問題発生
途中までやって、同時に設定しておくべきことが、他にもまだあることに気付く...。
-
-
- パラメーターの送信範囲
- ajax更新する範囲
-
フィルターに関する操作やイベントで、どのようなアクションが必要か。そして、そのアクションに必要な送信パラメーターと更新範囲を、決定しておく必要がある。表にまとめてみた。
操作、イベント | メソッド | 送信パラメーター、id属性 | 更新範囲、id属性 |
---|---|---|---|
最初のリスト表示 | list | すべて | 全体 |
フィルターを実行 | list_update | すべて、id="list_params" | ファイルリストのテーブルだけ更新、id="list_update" |
フィルター条件を追加 | add_filter | なし | フィルター条件の最終行に追加、id="filters" |
フィルター列の選択 | change_filter_column | 選択したフィルター列名称と行番号、id="filter_params#{行番号}" | _list_filter_condition.rhtmlが描画する部分、id="filter_update#{行番号}" |
- 特に、フィルター列の選択操作では、注意が必要だ。入力フォームを再描画する時に:name => "filter[#{session[:filter_count]}][column]"とやってしまうと、行番号の設定がマズい。(常に最終行の行番号が設定されてしまう...。)選択したフィルター条件の行番号を設定する必要がある。
id属性の構成図
list.rhtml
<div id="list_params">_list_filter.rhtml(フィルターの実行/解除/追加/削除という操作リンクの行)
<span id="filters">_list_filter_condition.rhtml(フィルター条件の行)
<span id="filter_params">
フィルター列のプルダウンリスト
</span><span id="filter_update">
_filter_列タイトル名.rhtml(列タイトル別の入力フォーム)
</span>
</span>
フィルター条件を追加のリンク
フィルターを実行/解除のリンク<div id="list_update">
<table>リスト表示する部分_listh.rhtml(列タイトル)
_listd.rthml(リストデータ)
</table>
前ページ/次ページのリンク
CSVファイルを新規登録のリンク
</div>
</div>