on Rails: Boxroom拡張作戦
[id:omochist:20061016:1161005206]で紹介した,Railsでできたアプロダ,Boxroom.何も弄らなくても十分に実用的ですが,ここはもっとユーザビリティを上げるべく,日本語のファイル名でもアップロードできるように拡張してみます.
日本語の名前でアップロードするとどうなるか
Boxroomで日本語の名前なファイルをアップロードすると,日本語の部分が"_"でエスケープされ,例えば「これはreportです.pdf」だと「______report____.pdf」になる.ちょっと嬉しくないよね.
文字コードどうすんの
Macからファイルをアップロードすると,ファイル名はUTF-8でエンコードされているので何も悲しい事はありません.しかし,Windowsからアップロードすると,ファイル名はShift-JISでエンコードされているので,ちょっと怖い.なので,文字コードの変換に関してはDBに格納するときにKconvなりなんなりで変換してやれば良いのです.もしかしたら,ActionPackあたりで自動的にUTF-8にしてくれてるかもしれないけれど.
つぎにダウンロードするときですが,これもやはりMacからダウンロードするのならそのままでも良い.だけど,Windowsからダウンロードするときは文字化けしちゃうので変換してやらないといけない.なので,OSを判断してUTF-8からShift-JISに変換する必要があります.
ちなみに,今回はKconvを使用しました.結構使いやすいので気に入りました.
ダウンロードするときのOSの判定
正直,これが一番しんどい.なんせ知識が無いものですから,ヘッダ情報にOS情報とか書いてるのかどうか,一切わかんない.なので,ここはJavaScripterのUchに教えてもらった
navigator.platform
を使用して,結構強引にやりました.もしJavaScriptを使用するのなら,本当はRJSとか使ってOSの判定をするべきだと思いますが,ちゃんとした方法を知らないものでどうしょうもない.
誰か教えてください><;
それじゃ,長くなるので,拡張した部分を続きに書きます.
どこを拡張するのよ
ざらっと書きます.
app/model/myfile.rb
アップロードするファイルの名前をUTF-8に変換し,日本語をエスケープしないようにする.
class Myfile < ActiveRecord::Base … def self.base_part_of(file_name) require 'kconv' # NOTE: File.basename doesn't work right with Windows paths on Unix # INCORRECT: just_filename = File.basename(file_name.gsub('\\\\', '/')) # get only the filename, not the whole path name = Kconv.toutf8(file_name) # UTF-8に変換 name.gsub(/^.*(\\|\/)/, '').gsub(/[\s\-]/, '_') # エスケープする文字を変更 end end
app/controllers/file_controller.rb
引数で渡されたplatformによりOSを判別し,文字コードの変換を行う.Linuxの各ディストリが使用している文字コードまでは判別できないので,勘弁してくれ*1.とりあえずLinuxはUTF-8で(w
class FileController < ApplicationController … def download require 'kconv' # Log the 'usage' and return the file. usage = Usage.new usage.download_date_time = Time.now usage.user = @logged_in_user usage.myfile = @myfile platform = params[:platform] # コレについては後述 filename = @myfile.filename if platform =~ /mac/i ; # macなら何もしなくて良い elsif platform =~ /win/i # WindowsならShiftJISに変換 filename = Kconv.tosjis(filename) end if usage.save send_file("#{RAILS_ROOT}/uploads/" + @myfile.id.to_s, :filename => filename) # ここもちょっと変更 end end … end
app/views/layouts/folder.rhtml
folder.rhtmlで,platformを取得しておく.わざわざfolder.rhtmlで取得する意味があるかは分からないけれど,次に編集するlist.rhtmlの適当なところにscriptタグを埋め込むよりは,headの中に書いた方が気がしたので.
<html> <head> <title>Boxroom</title> (略) <script type="text/javascript"> if(IE) { window.onload = ResizeContentDiv; window.onresize = ResizeContentDiv; } var platform = navigator.platform; </script> </head> …
app/views/folder/list.rhtml
言ってみればごり押しで,document.writeでごりごりと書く.どうなってるかはscriptを読んでもらえればわかると思うけれど,
<a href="/file/download/3?platform=MacOS">とあるレポート.pdf</a>
のようなものを書きたいわけ.
これの10倍は良い方法があるに違いない.
… <% for myfile in @myfiles %> <tr class="<%= cycle('even', 'odd') %>"> <td><%= image_tag('file') %></td> <td> <script type="text/javascript" language="javascript"> <!-- document.write("<a href=\"/file/download/<%= myfile.id %>?platform=" + platform + "\"><%= h(myfile.filename) %></a>") --> </script> </td> <td><%= myfile.filesize %> KB</td> <td><%= myfile.date_modified %></td> <td> …