CSVサーバー0.1

CSVサーバーは、表計算ソフトで作成した資料を、社内のネットワークで簡単に公開できることを目指して作成中のWEBアプリケーションです。Ruby on Railsの勉強も兼ねているので、まだまだ不完全な部分も多く、思い通りの動作をしない可能性もあります。

唯一の特徴は、社内向けに閲覧制限を設定することが可能なことです。表の中にpath列を設定しておくと、その行はpath列の部署名のユーザーのみ閲覧可能になります。その詳細については、以前の日記の以下のタイトルを紹介しておきます。

また、アップロードしたCSVファイルを柔軟に検索(フィルタ)できるように心掛けました。検索(フィルタ)機能の詳細については、以下のタイトルを紹介しておきます。

CSVサーバーへのログイン

テスト用の運用ページから、以下のユーザーでログインすることがきます。自由に試して頂いて結構です。(システム管理者でログインすれば全ての権限が手に入ります。その場合、好奇心旺盛に設定を変更してしまうと、CSVサーバーはダウンしてしまうかもしれませんが...。)

ログイン名 パスワード 権限 閲覧可能な部署 管理部門
yamada yamada CSVファイルの閲覧のみ /株式会社RAILS/営業1部/営業1課/, /株式会社RAILS/営業1部/営業3課/ 無し
suzuki suzuki CSVファイルのアップロードと閲覧 /株式会社RAILS/ 経理
satou satou CSVファイルのアップロードと閲覧 /株式会社RAILS/ 人事部
zarigani zarigani システム管理者であり、全ての権限 /株式会社RAILS/ 総務部、人事部、経理

productionモードまでの更新履歴

bootstrapの実行と、権限の設定。これを忘れると、Admin権限以外では正常に機能しなくて悩むことになる。
フィルターの比較演算子のデフォルトをブランクではなく、よく使いそうな演算子に変更した。
filter_setsテーブルをブランク無しの状態に変更した。
その変更に伴い、検索アイテムを未入力の場合(filter_itemがブランクまたは空白文字の場合)は、フィルター処理を無視するようにした。以下のようにやってみたが、とても分かり難い処理になってしまった...。
app/models/filter_sql.rb
モデル
  def self.human_compair_sql(column, item, id)
    f = Filtersql.find(id)
    
    # itemが未入力または、空白文字の時は、フィルター無しの条件を設定する。
    item_eval = eval(f.item || '')
    if item_eval.nil? && (item.empty? || /\s+/ =~ item)
      f = Filtersql.find(20)
      item = eval(f.item || '')
    end
    
    # 必ず、option = 、item = の順に実行すること。
    # eval("AND '#{end_at_period(item)}'")の場合はitemの値に影響されるため。
    option = eval(f.option || '')
    item = item_eval || item || '%'
    
    #"(#{f.not_op} #{column} #{f.operator} '#{f.wild1}#{item}#{f.wild2}' #{option})"
    sql = "(#{f.not_op} #{column} #{f.operator} ? #{option})"
    sanitize_sql([sql, "#{f.wild1}#{item}#{f.wild2}"])
  end
管理部門、アップロード担当者のフィルターのデフォルト値を自分自身の設定にする。選択した自分自身の設定が存在しない場合はブランクになる。
app/views/csvs/_filter_management_section_id.rhtml
ビュー
<% options = Csv.find(:all, :include => :management_section).map do |c| 
               [c.management_section.name, c.management_section_id]
             end.uniq.unshift(@no_select) %>
<% selected_item = current_user.management_sections[0].id rescue nil %>
<%= select_tag :filter_item, options_for_select(options, selected_item), 
               :name => "filter[#{@filter_count}][item]" %>

<% items = Filterset.find_by_name('select').filtersqls.map{|f| [f.name, f.id]} %>
<%= select_tag :filter_id, options_for_select(items, params[:filter_id].to_i), 
               :name => "filter[#{@filter_count}][id]" %>
app/views/csvs/_filter_user_id.rhtml
ビュー
<% options = Csv.find(:all, :include => :user).map do |c| 
               ["#{c.user.lastname} #{c.user.firstname}", c.user_id]
             end.uniq.unshift(@no_select) %>
<%= select_tag :filter_item, options_for_select(options, current_user.id), 
               :name => "filter[#{@filter_count}][item]" %>

<% items = Filterset.find_by_name('select').filtersqls.map{|f| [f.name, f.id]} %>
<%= select_tag :filter_id, options_for_select(items, params[:filter_id].to_i), 
               :name => "filter[#{@filter_count}][id]" %>
CSVファイルへのリンクをクリックした時は、新規ウィンドウで表示するようにした。以下のように:popup=>trueオプションを追加するだけでOK。ちなみに:popup => ['new_window_name', 'height=300,width=600']のように指定すれば、ウィンドウのタイトルとサイズも指定可能。
<%= link_to h(listd.file_name), 
            {:controller => 'displays', :action=>'list', 
             :table => listd.csv_table, :editable => listd.editable}, 
            :popup => true %>
CSVリストページで、編集、削除の操作をしても、現在の並べ替え方法とページ番号を維持するようにした。
ページ切り替えのリンクを上下に表示するようにした。
アップロードするCSVファイルサイズの制限を2MBに設定。
app/models/csv.rb
モデル
...(途中省略)...
  def validate_on_create
    errors.add(:file_size, "...ファイルが大き過ぎます。2MB以下でお願いします。") if @file && @file.size > 2*1024*1024
  end
  
  # Tempfileオブジェクトをインスタンス変数に保存する。
  # save()や、update_attributes()の時、呼び出される。
  def tempfile=(file)
    return if file.nil? || file.size == 0
    @file = file
    self.file_name = file.original_filename.gsub(/^(.)|\W/, '_\1')
    self.file_size = file.size
  end
...(途中省略)...
app/views/csvs/_form.rhtml
ビュー
<%= error_messages_for 'csv' %>

<table class="csv_form">
<!--[form:csv]-->
<tr>
<% if ['new', 'create'].include?(controller.action_name) %>
  <th align="right" rowspan="2"><label for="csv_tempfile">ファイル:</label></th>
  <td <%= "class='fieldWithErrors'" if @csv.errors.on(:file_name) %>>
    <%= file_field 'csv', 'tempfile' %>
    <small>
    <%= "重複ファイル名: #{@csv.file_name}" if @csv.file_name && @csv.errors.on(:file_name) %>
    </small>
  </td>

不満な要素

  • フラッシュメーセージを表示し続けるべきか?一定時間経過後に表示を隠したい。
  • ファイル名の先頭が、_(アンダーバー)で始まっていることに気付き難い。だから「ファイル名が...で始まる」でフィルターしても、思うような結果が返らず、悩んでしまう。
  • フィルターがセットされた状態で編集、削除を実行すると、フィルターが解除されてしまう。
  • 現状は、ファイル名は重複してはならないので、時間を表現する名前と、内容を表現する名前を組み合わせて、ファイル名を命名する必要がある。お勧めは、時間情報、内容情報の順にファイル名を命名する方法。(並び替えは時間順に表示された方が便利な気がする。内容を絞り込みたい時は、フィルターを利用する。)
  • しかし、異なる意味の情報は項目を分けるべきでもあり、アップロードした時に時間的情報を入力してもらい、内容情報と時間情報を組み合わせてデータベースに登録するという手段もある。この場合、以下のようなデメリットも発生する。
    • 毎回、時間情報を入力するのが手間になる。
    • 自分の保管するファイルと、アップロードしてあるファイルの対応が、分かり難くなる可能性がある。