Railsで画像データをMySQLに保存する方法
概要
DBにMySQLを使用したRailsを開発に使っておりますが、ある時画像を取り込む必要が出てきました。その時に調べたこととその結果をまとめてみました。
- 目次
- 環境
- マイグレーション
- 取り込み
- 表示
マイグレーション
まずはマイグレーションを使ってテーブルの準備。いつも通りです。
$ cd RAILS_ROOT $ ./script/generate migration Image $ vi ./db/migrate/VERSION_image.rb
class Image < ActiveRecord::Migration def self.up create_table :images do |t| t.binary :image end end def self.down drop_table :images end end
$ rake db:migrate
これで、カラムにIDとimageを持つテーブルimagesが出来ました。次はこのテーブルに画像データを突っ込む*1ためにscaffoldを作成します。なんと、ここでRails2.0ではscaffold作成時にmigrationもやってくれるらしいことに気づく。まじっすか。
悲しんでても仕方ないので、rollbackをしかける。
$ rake db:rollback
よし、テーブルはなくなった。気を取り直してscaffoldです。
$ ./script/generate scaffold Image image:binary $ rake db:migrate $ ./script/server
http://localhost:3000/ にアクセスし、サーバが起動していることを確認出来たらいよいよじっそうです。
取り込み
画像があるディレクトリをHOGEとします。この画像を取得するのに、RMagickを使用します。とりあえず、画像を取得して別名に保存するスクリプトを書いて実験。データベースには手でデータを入れる。Imageモデルにこんなコードを書く。
require 'rubygems' require 'RMagick' class Image < ActiveRecord::Base def save png = Magick::ImageList.new("HOGE/hogehoge.png") image = Image.new image.image = png.to_blob image.save! end end
こんな感じで試してみる。いや、この作り方がうまくないのはわかるんだが…ま、テスト用ってことで。とりあえず画像が保存されることを確認した。バイナリデータはこれが正しく保存されているかどうか確認できないから嫌だ…
表示
今度はDBから画像を取得して画面に表示する。さっきと同じクラスの中にgetメソッドを作ります。
def get id image = Image.find(id) img = Magick::Image.from_blob(image.image).shift.to_blob end
コントローラはこんな感じ。send_dataしてあげるのがポイント。画像表示のタイミングでget_imageメソッドにアクセスして、ビューにバイナリ画像を送るようなイメージです。
def get_image img = Image.new @image = img.get send_data(@image, :disposition => "inline", :type => "image/png") end
最後にビューです。indexビューです。
<h1>Image</h1> <%= image_tag(url_for(:controller => 'images', :action => 'get_image', :format => :png)) %>
これで http://localhost:3000/images/ にアクセスすると、無事画像が表示されていました!うーん。blobはphpで大分苦労した覚えがあるんですが、Railsだと割とあっさりいけてしまいました。
つーことで、目的は達成したので業務に戻りますです。
*1:imageカラムの属性にbinaryを選ぶとblobとなりますが、容量が64KBまでとなります。もっと大きなサイズの画像を扱いたい場合はまた別の方法で。