画像ファイルをアップロードして自由に表示したい!その3
今度は、アップロードしたファイルをデータベースではなく、ファイルとして保存してみる。ファイルを保存する位置は、public/filesフォルダにした。*1(filesフォルダを新規作成した。)まずはアップロードするファイルは一つだけに限定してやってみた。
ファイルは、以下のように保存される。
コントローラー
ファイルの保存や読み出しは、モデルやビューが処理するので、コントローラーに追記する必要はなし。scaffoldが生成したコードのままでOK(前回までに追加したputs_image、convert_temp_fileメソッドは不要なので削除した。)
モデル
- ファイルの保存、保存したファイルまでのパスの管理は、モデルが処理する。
- after_save :save_file で、saveの後、save_fileメソッドが呼び出される。
- after_destroy についても同様。
- image_sourceメソッドは、image_tagのルールに合わせた画像ファイルまでのパスを取得するメソッド。
- file_pathメソッドは、fileプロジェクト以下の画像ファイルまでのフルパスを取得するメソッド。
class Software < ActiveRecord::Base after_save :save_file after_destroy :destroy_files def validate errors.add(:file, "アップロードするファイルを指定してください。") if @file.nil? || @file.size == 0 # content_typeが、image/ で始まっていなければ、エラーにする。 errors.add(:file, "画像ファイルではありません。") unless @file.nil? || /^image\// =~ @file.content_type end # new()やupdate_attributes()の時、呼び出される。 def temp_file=(file) return if file.nil? || file.size == 0 @file = file @old_file_path = file_path self.file_name = file.original_filename self.file_type = file.content_type #self.file_data = file.read end # saveメソッドの後に呼び出される。 def save_file File.delete(@old_file_path) rescue nil File.open(file_path, "wb") do |f| f.write(@file.read) end end # destroyメソッドの後に呼び出される。 # 削除されたレコードのid、file_name等にアクセス可能。 def destroy_file # ファイルが存在しない場合でも、rescue nilでエラーを無視する。 File.delete(file_path) rescue nil end # RAILS_ROOTからのディレクトリを取得する。 # "#{RAILS_ROOT}/piblic"でなくてもOKのようだ。 def file_path "public" + image_source end # image_tagがファイルを参照するルールに合わせたパスを返す。 # デフォルトは、public/images/から参照する。 # 例)"files/1_test.png" >> "public/images/files/1_test.png" # もし先頭が/で始まれば、pblic/から参照する。 # 例)"/files/1_test.png" >> "public/files/1_test.png" def image_source # 新規作成の時、idがnilなので、rescue nilでエラーを無視する。 "/files/#{id}_#{file_name}" rescue nil end end
ビュー
- 画像ファイルの表示をする image_tag の部分だけ抜き出した。
- 画像を表示するときは、保存したファイルまでのパスを指定すればOK。
<%#------ app/views/softwares/show.rhtml ------%> ...(途中省略)... <%= image_tag @software.image_source, :alt => @software.file_name %> ...(途中省略)...
- 大きさを指定することも出来る。(32x32のxは、xyzのx。)
<%#------ app/views/softwares/list.rhtml ------%> ...(途中省略)... <%= image_tag software.image_source, :alt => software.file_name, :size => '32x32' %> ...(途中省略)...
*1:image_tagがファイルを参照する時、publicフォルダが指定されているようなので、publicフォルダ内が無難。