Ruby on Rails: ファイルアップロード機能を作る Rails 2.1.0版

Railsでファイルをアップロードするところを参考にさせていただいた。
"Ruby on Rails: ファイルアップロード機能を作る" http://www.negisio.net/?p=30
Railsなどの環境が変わってそのままでは動かなかったので、修正して動かせることができました。

Rails 2.1.0
SQLite 3使用
will_paginate使用

$ rails uploader

paginateは、rails 2.0より標準で使われなくなった。そのためwill_paginateを使う。

今日現在(2008/8/11)は、will_paginateはgemでインストールする。

$ gem install will_paginate

そしてRailsのenvironment.rbの最後に以下を追加する。

require 'will_paginate'

Rails pluginはサポートしなくなったようだ。

そのほか

$ cat db/migrate/2008011xxxxx_create_attachments.rb
class CreateAttachments < ActiveRecord::Migration
  def self.up
    create_table :attachments do |t|
      t.column(:content_type, :string)
      t.column(:filename, :string)
      t.column(:size, :integer)
      t.column(:data, :binary)
    end
  end

  def self.down
    drop_table :attachments
  end
end

コントローラー

$ cat app/controllers/attachment_controller.rb
class AttachmentController < ApplicationController
    # 新規アップロード画面を作る用。
  def new
  end

  # アップロード処理
  def create
    @uploaded = params[:upload]
    Attachment.create(
      :content_type => @uploaded['file'].content_type,
      :filename => @uploaded['file'].original_filename,
      :size => @uploaded['file'].size,
      :data => @uploaded['file'].read)
    redirect_to(:action => :list)
  end

  # ファイル一覧表示
  def list
    @attachments = Attachment.paginate(:page => params[:page], :per_page => 10, :order => "id desc")
  end

  # ファイルダウンロード用。
  # 注)日本語ファイル名は文字化けする。
  #   右クリックで「対象をファイルに保存」するとファイル名がちゃんと出ない。
  def view_file
    attachment = Attachment.find(params[:id])
    send_data(attachment.data, {:filename => attachment.filename,
                             :type => attachment.content_type})
  end

  # ファイル削除
  def destroy
    @attachment = Attachment.find(params[:id])
    @attachment.destroy
    redirect_to(:action => :list)
  end

end

ビュー

$ cat app/views/attachment/list.rhtml
<h1>attachments list</h1>
<table>
  <tr>
    <th>id</th>
    <th>filename</th>
    <th>content_type</th>
    <th>action</th>
  </tr>
<% @attachments.each do |attachment| %>
  <tr>
    <td><%= h(attachment.id) %></td>
    <td><%= h(attachment.filename) %></td>
    <td><%= h(attachment.content_type) %></td>
    <td><%= link_to('(download)',
                {:action => 'view_file',
                 :id => attachment.id})
     %>
    <%= link_to('(destroy)',
                {:action => 'destroy',
                 :id => attachment.id})
     %></td>
  </tr>
<% end %>
</table>

<%= will_paginate @attachments, :prev_label => 'prev', :next_label => 'next' %>
<br /><br />
<%= link_to('new', {:action => 'new'}) %>
$ cat app/views/attachment/new.rhtml
<h1>add attachment</h1>
<% form_tag({:action => 'create'}, :multipart => true) do %>
<%= file_field( :upload, 'file') %>
<%= submit_tag('upload') %>
<% end %>

ちょっと考えればわかることなんだけれど、will_paginateの使い方と、rails 2.1の使い方をよく間違えるので記録しておく。