RailsにはPaperclipというファイルアップロードプラグインがあり、Marcel Molina Jr.さん謹製のAWS::S3というgemを使用したS3へのアップロードもサポートしているのですが、今回はせっかくAmazonの公式ruby sdkが公開されたので、そちらを利用したPaperclip拡張である@igor-alexandrovさんのpaperclip-awsを使用してS3ファイルアップロードを試してみます。
PaperclipはImageMagickを使用するので、まずImageMagickをインストールします。
yumからだとバージョンが古い場合があるので、ソースからインストールします。
# cd /usr/local/src # wget ftp://ftp.imagemagick.org/pub/ImageMagick/ImageMagick.tar.gz # tar xzvf ImageMagick.tar.gz # cd ImageMagick-6.7.1-2 # ./configure # make # make install
次にldconfigでライブラリの更新をシステムに知らせます。
# ldconfig /usr/local/lib
Gemfileに以下のgemをインストールします。
- RMagick(ImageMagickのRubyラッパー)
- Paperclip(ファイルアップロードプラグイン)
- paperclip-aws(paperclipでのS3アップロード機能拡張)
$ vi Gemfile
gem 'rmagick' gem "paperclip", "~> 2.3" gem "papepclip-aws"
gemのインストールと更新を行います。
$ bundle install vendor/bundle $ bundle update
ImageMagickへのパスを通します。
$ vi config/environments/development.rb
Paperclip.options[:command_path] = "/usr/local/bin/"
railsでScaffoldを作成してみます。
今回は簡易ブログを作成する想定で、blogというモデルのscaffoldを作成しました。
$ rails g scaffold blog title:string description:text
モデルにファイルアップロードの項目を追加します。
paperclipのhas_attacched_fileメソッドの引数では、デフォルトのpaperclipの項目以外にpaperclip-awsで追加されたs3用の項目も指定できます。
項目についてはここで解説されています。
ここではphotoという名前で追加してみます。このブログの鈍行編1の設定でaws.ymlにアクセスキーとシークレットキーしか設定していなかったので、今回その他の設定は直接指定していますが、これらもaws.ymlに含めてしまうこともできます。以下赤字が追加した部分です。
$ vi app/models/blog.rb
class Blog < ActiveRecord::Base
def self.s3_config
@@s3_config ||= YAML.load(ERB.new(File.read("#{Rails.root}/config/aws.yml")).result)[Rails.env]
end
has_attached_file :photo,
:styles => {
:thumb => [">75x"],
:medium => [">600x"]
},
:storage => :aws,
:s3_credentials => {
:access_key_id => self.s3_config['access_key_id'],
:secret_access_key => self.s3_config['secret_access_key'],
:endpoint => 's3-ap-northeast-1.amazonaws.com'
},
:s3_bucket => 'myfirst-bucket',
:s3_host_alias => self.s3_config['s3_host_alias'],
:s3_acl => :public_read,
:s3_protocol => 'http',
:path => "images/:id/:style/:data_file_name"
end
続いて、viewに画像ファイルの項目を追加します。
viewは通常のpaperclipのviewの書き方とまったく同じです。
まずは、入力画面にphoto属性のファイル選択フィールドを追加します。
$ vi app/views/blogs/_form.html.erb
<%= form_for(@blog, :html => { :multipart => true } ) do |f| %> <% if @blog.errors.any? %> <div id="error_explanation"> <h2><%= pluralize(@blog.errors.count, "error") %> prohibited this blog from being saved:</h2> <ul> <% @blog.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %> <div class="field"> <%= f.label :title %><br /> <%= f.text_field :title %> </div> <div class="field"> <%= f.label :description %><br /> <%= f.text_area :description %> </div> <div class="field"> <%= f.label :photo %><br /> <%= f.file_field :photo %> </div> <div class="actions"> <%= f.submit %> </div> <% end %>
詳細画面や完了画面で写真が確認できるようにを表示するようにphotoのimgタグを追加します。
$ vi app/views/blogs/show.html.erb
<p id="notice"><%= notice %></p>
<p>
<b>Title:</b>
<%= @blog.title %>
</p>
<p>
<b>Description:</b>
<%= @blog.description %>
</p>
<%= image_tag @blog.photo.url(:medium) %>
<%= link_to 'Edit', edit_blog_path(@blog) %> |
<%= link_to 'Back', blogs_path %>
一覧画面にサムネイルを表示するようにサムネイル用のimgタグを追加します。
$ vi app/views/blogs/index.html.erb
<h1>Listing blogs</h1> <table> <tr> <th>Title</th> <th>Description</th> <th>Photo</th> <th></th> <th></th> <th></th> </tr> <% @blogs.each do |blog| %> <tr> <td><%= blog.title %></td> <td><%= blog.description %></td> <td><%= image_tag blog.photo.url(:thumb) %></td> <td><%= link_to 'Show', blog %></td> <td><%= link_to 'Edit', edit_blog_path(blog) %></td> <td><%= link_to 'Destroy', blog, :confirm => 'Are you sure?', :method => :delete %></td> </tr> <% end %> </table> <br /> <%= link_to 'New Blog', new_blog_path %>
次に、paperclip用の項目をDBに追加するためのマイグレーションファイルを作成します。
$ rails g migration add_photo_columns_to_blog invoke active_record create db/migrate/20110805111437_add_photo_columns_to_blog.rb $ vi db/migrate/20110805111437_add_photo_columns_to_blog.rb
class AddPhotoColumnsToBlog < ActiveRecord::Migration def self.up add_column :blogs, :photo_file_name, :string add_column :blogs, :photo_content_type, :string add_column :blogs, :photo_file_size, :integer add_column :blogs, :photo_updated_at, :datetime end def self.down remove_column :blogs, :photo_file_name remove_column :blogs, :photo_content_type remove_column :blogs, :photo_file_size remove_column :blogs, :photo_updated_at end end
マイグレーションを行います。
$ rake db:migrate (in /var/www/html/myfirstcloud) == CreateBlogs: migrating ==================================================== -- create_table(:blogs) -> 0.0011s == CreateBlogs: migrated (0.0014s) =========================================== == AddPhotoColumnsToBlog: migrating ========================================== -- add_column(:blogs, :photo_file_name, :string) -> 0.0007s -- add_column(:blogs, :photo_content_type, :string) -> 0.0004s -- add_column(:blogs, :photo_file_size, :integer) -> 0.0005s -- add_column(:blogs, :photo_updated_at, :datetime) -> 0.0004s == AddPhotoColumnsToBlog: migrated (0.0028s) =================================
これで、S3にアップロードすることができるようになりました。
ブラウザで確認してみます。
http://IPアドレス/blogsにアクセスすると、以下のようにscaffoldで作成された一覧画面が表示されます。
New Blogのリンクをクリックして、新規登録画面を表示すると、
画像のアップロードのフィールドがあることが確認できます。
テキストを入力し、画像を選択したらCreate Blogボタンをクリックします。
すると、登録完了の画面として、アップロードした写真が表示されます。
また、一覧画面に戻ると、一覧にもサムネイルが表示されているのがわかります。
表示されている画像のURLをみると以下のようにS3からホストされていることが確認できます。
http://s3-ap-northeast-1.amazonaws.com/myfirst-bucket/images/1/thumb/:data_file_name簡単にS3ファイルアップロードを実装することができました。
本日はこれにて。