画像ファイルをアップロードして自由に表示したい!その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フォルダ内が無難。