ファイルアップロード
今まで何度となくファイルアップロードを書いては忘れ、その都度調べてて、いい加減疲れてきたのでここにメモる。今後はここをコピペする方向で。
基本的にこちらのコピーなので、要respond_to_parentプラグイン。説明もそちらを参照。ここには単にコードだけ置いときます。
できることは、画面遷移無しのファイルアップロードと、フォームの下に表示されているファイルリストの非同期な更新。
テーブルはこんな感じ
class CreateUploadedFiles < ActiveRecord::Migration def self.up create_table :uploaded_files do |t| t.column :filename, :string t.column :content_type, :string t.column :size, :integer t.column :data, :binary t.column :created_at, :integer end end def self.down drop_table :uploaded_files end end
ビュー
アップロードフォームを持つ静的な部分と、動的に更新されるファイルリストはテンプレートを分けておく
attach.rhtml
<iframe name="frame" style="width:0;height:0;border:0;"></iframe> <% form_tag({:action => 'upload'}, {:multipart => true, :target => 'frame'}) do -%> <%= file_field_tag 'file' %> <%= submit_tag _('Upload') %> <% end -%> <div id='uploaded_file_list'> <%= render :partial => 'uploaded_file_list' %> </div>
_uploaded_file_list.rhtml
<% unless @uploaded_files.empty? -%> <ul> <% @uploaded_files.each do |uploaded_file| -%> <li><%= uploaded_file.filename %></li> <% end -%> </ul> <% else -%> <%= _('No uploaded file exists.') %> <% end -%>
コントローラー
def attach @uploaded_files = UploadedFile.find :all end def upload file = params[:file] UploadedFile.create :filename => file.original_filename, :content_type => file.content_type, :size => file.length, :data => file.read @uploaded_files = UploadedFile.find :all responds_to_parent do html = render_to_string :partial => 'uploaded_file_list' render :update do |page| page.replace_html 'uploaded_file_list', html end end end
[追記]
画面遷移なしでファイルアップロードする方法 と Safariの注意点 (groundwalker.com) にかかれてあるとおりの現象がおきたので修正しました。