Railsで画像をアップロードするときはどうやっているんでしょうか。
Fleximageというプラグインがあります。よいAPIだと思うのですが、あまり使っている人がいないようなので紹介します。
ここでは1からサンプルRailsアプリケーションを作成しながらFleximageの使い方を紹介します。順番にコマンドを実行・コードを変更していくと動くように書いてあります。
まず、sampleというRailsアプリケーションを作成します。
% cd /tmp % rails sample % cd sample
次に、Fleximageをインストールし、画像用のテーブルを作成します。
% script/plugin install git://github.com/Squeegy/fleximage.git % script/generate scaffold photo title:string image_filename:string image_width:integer image_height:integer % rake db:migrate
以下のカラムは特別なカラムです。Fleximageは以下のカラムが定義されていると、そこに値を設定してくれます。
これらはすべて省略可能です。今回は、せっかくなので、すべて定義しました。
Fleximageを使うため、モデルを以下のように変更します。
app/models/photo.rb:
class Photo < ActiveRecord::Base acts_as_fleximage :image_directory => 'public/images/uploaded' end
これで、アップロードされた画像は"#{RAILS_ROOT}/public/images/uploaded"以下に保存されます。
ここからは、コードを変更し、アプリケーションを動かし、動作を確認しながら進めていきます。そのため、ここでサーバを起動しておきます。
% script/server
http://localhost:3000/photos/にアクセスすると以下のような見慣れたscaffoldの画面になるので、「New Photo」リンクから画像アップロードフォームへ進みます。

scaffoldのフォームでは画像をアップロードできないので、app/views/photos/new.htmlを以下のように変更します。
app/views/photos/new.html:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<h1>New photo</h1> <% form_for(@photo, :html => {:multipart => true}) do |f| %> <%= f.error_messages %> <p> <%= f.label :title %><br /> <%= f.text_field :title %> </p> <p> <%= f.label :image_file %><br /> <%= f.file_field :image_file %> </p> <p> <%= f.submit 'Create' %> </p> <% end %> <%= link_to 'Back', photos_path %> |
これで、フォームは以下のようになります。

タイトルとアップロードする画像のパスを指定して「Create」ボタンを押します。
画像がアップロードされ、ファイル名やサイズが設定されていることが確認できます。

せっかく画像をアップロードしたので、アップロードした画像も表示するようにします。app/views/photos/show.html.erbに以下を追加します。ここでは、タイトルの下に追加しました。
app/views/photos/show.html.erb:
1 2 3 |
<p> <%= image_tag(photo_path(@photo, :format => "png")) %> </p> |
PNGフォーマットを指定しているので、コントローラ側でPNGフォーマットを受けつけるようにします。
app/controllers/photos_controller.rb:
1 2 3 4 5 6 7 8 9 |
def show @photo = Photo.find(params[:id]) respond_to do |format| format.html # show.html.erb format.xml { render :xml => @photo } format.png # <- 追加 end end |
PNGフォーマットのビューを作ります。ここが、FleximageのAPIのよいところです。
Fleximageを使ったビューは「#{アクション名}.#{フォーマット}.flexi」というファイル名になります。今回の場合だと、「show.png.flexi」になり、以下のような内容になります。
app/views/photos/show.png.flexi:
1 2 3 |
# -*- ruby -*- @photo.operate do |image| end |
これで、http://localhost:3000/photos/1.pngで画像を表示することができるようになりました。画像表示ページは以下のようになります。

画像表示ページではアップロードされた画像をそのまま表示しました。画像一覧ページでは画像のサムネイルを表示することにします。
サムネイル画像はhttp://localhost:3000/photos/1/thumbnail.gifで表示するようにします。そのため、まず、config/routes.rbを変更します。
config/routes.rb:
1 |
map.resources :photos, :member => {:thumbnail => :get} |
これで、thumbnail_photo_pathが使えるようになるので、index.html.erbを書き換えます。
app/views/photos/index.html.erb:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<h1>Listing photos</h1> <table> <tr> <th>Title</th> <th>Thumbnail</th> <th colspan="3">Action</th> </tr> <% @photos.each do |photo| %> <tr> <td><%=h photo.title %></td> <td><%= image_tag(thumbnail_photo_path(photo, :format => "gif") %></td> <td><%= link_to 'Show', photo %></td> <td><%= link_to 'Edit', edit_photo_path(photo) %></td> <td><%= link_to 'Destroy', photo, :confirm => 'Are you sure?', :method => :delete %></td> </tr> <% end %> </table> <br /> <%= link_to 'New photo', new_photo_path %> |
ここでは意味もなくフォーマットにgifを指定していますが、これはFleximageが画像フォーマットを簡単に変更できることを示すためです。
コントローラにGIFフォーマットに対応したthumbnailアクションを定義します。
app/controllers/photos_controller.rb:
1 2 3 4 5 6 7 |
def thumbnail @photo = Photo.find(params[:id]) respond_to do |format| format.gif end end |
サムネイルのGIF画像用のビューは以下のようになります。とてもすっきり書けています。
app/views/photos/thumbnail.gif.flexi:
1 2 3 4 |
# -*- ruby -*- @photo.operate do |image| image.resize('80x60') end |
変更した一覧ページを表示するとこうなります。

アップロードした画像がサムネイルとして表示されています。
すっきりしたAPIのRails用画像アップロードプラグインFleximageを紹介しました。
ここでは触れませんでしたが、Fleximageは機能が豊富でカスタマイズ性にも優れています。例えば、アップロードされた画像を表示するときに影をつけたり、文字を入れたりといろいろ加工することができます。また、ファイルではなく、データベースに画像を保存することもできます。
Fleximageは日本語の情報がほとんどないのが不思議ですね。あまり使われていないのかもしれません。
ImageMagickを使って画像に影をつけるシェルスクリプトです。これを使うと、このページのスクリーンショットについているような影をつけることができます。
add-shadow.sh:
1 2 3 4 5 6 7 8 9 |
#!/bin/sh
if [ $# != 2 ]; then
echo "Usage: $0 INPUT SHADOWED_OUTPUT"
exit 1
fi
convert $1 \( +clone -background black -shadow 80x6 \) \
+swap -background none -layers merge +repage $2
|
このように使います。
% ./add-shadow.sh image.png shadowed-image.png