Rails3+paperclipでファイルアップロード
Ruby界のファイルアップロードのライブラリはいくつかあるけど、PaperclipとcarrierwaveがTOP2らしい。
どっちも歴史、機能、活発度的に大きく変わらないようだけど以下の点からpaperclipを使って見ることにした。
- 要件はどちらも満たしている(Rails、S3対応くらい)
- 使い方をざっくり見たところ、paperclipのほうがシンプルに見える(あまり変わらない)。
- carrierwaveはpaperclipからの移行I/Fも備えているので、paperclipが嫌になったら移行すればいい
動作まで
とりあえずS3は置いておいて、publicディレクトリ配下にアップロードするようにしてみる。
gemの追加
Gemfile
gem "paperclip", "~> 3.0"
ImageMagickのインストール
brew install imagemagick
modelの修正
User.rb
class User < ActiveRecord::Base attr_accessible :email, :name, :password attr_accessible :avatar has_attached_file :avatar, :styles => { :medium => "300x300>", :thumb => "100x100>" }
とりあえず適当にドキュメントの見本通り。
migrateファイル修正 & migrate
class CreateUsers < ActiveRecord::Migration def change create_table :users do |t| t.string :email, :limit => 60, :null => false t.string :name, :limit => 20, :null => true t.string :password_digest, :limit => 100, :null => false t.attachment :avatar t.timestamps end
bundle exec rake db:migrate
こんな感じになる。
mysql> desc users; +---------------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------------------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | email | varchar(60) | NO | UNI | NULL | | | name | varchar(20) | YES | | NULL | | | password_digest | varchar(100) | NO | | NULL | | | avatar_file_name | varchar(255) | YES | | NULL | | | avatar_content_type | varchar(255) | YES | | NULL | | | avatar_file_size | int(11) | YES | | NULL | | | avatar_updated_at | datetime | YES | | NULL | | | created_at | datetime | NO | | NULL | | | updated_at | datetime | NO | | NULL | | +---------------------+--------------+------+-----+---------+----------------+
テストも書いてみる
http://rubydoc.info/gems/paperclip/Paperclip/Shoulda/Matchers
spec_helper.rb
require "paperclip/matchers" Spork.prefork do ~snip~ RSpec.configure do |config| config.include Paperclip::Shoulda::Matchers ~snip~
user_spec.rb
describe User do ~snip~ describe "when avatar is not valid" do it { should validate_attachment_content_type(:avatar). allowing('image/png', 'image/gif', 'image/jpeg', 'image/jpg').rejecting('text/plain', 'text/xml') } it { should validate_attachment_size(:avatar). less_than(1.megabytes) } end ~snip~
動いた。当然エラったけど。
Failures: 1) User when avatar is not valid Failure/Error: allowing('image/png', 'image/gif', 'image/jpeg', 'image/jpg').rejecting('text/plain', 'text/xml') } Expected avatar: Accept content types: image/png, image/gif, image/jpeg, image/jpg All were accepted successfully. Reject content types: text/plain, text/xml text/plain, text/xml were accepted. # ./spec/models/user_spec.rb:152:in `block (3 levels) in <top (required)>' 2) User when avatar format is not valid Failure/Error: less_than(1.megabytes) } Attachment avatar must be between and 1048576 bytes # ./spec/models/user_spec.rb:154:in `block (3 levels) in <top (required)>' Finished in 2.47 seconds 34 examples, 2 failures Failed examples: rspec ./spec/models/user_spec.rb:151 # User when avatar format is not valid rspec ./spec/models/user_spec.rb:153 # User when avatar format is not valid
user.rbに追記
class User < ActiveRecord::Base attr_accessible :username, :email, :name, :password, :avatar_content_type attr_accessible :avatar has_attached_file :avatar, :styles => { :medium => "300x300>", :thumb => "100x100>" } has_secure_password validates_attachment_size :avatar, :less_than => 1.megabytes validates_attachment_content_type :avatar, :content_type => ['image/jpeg', 'image/jpg', 'image/png', 'image/gif']
これで、テスト通った。ほんとにこれで動くのか?
テストしてみる。
<%= form_for(@user) do |f| %> <%= render 'shared/error_messages' %> <%= f.label :name, t('users.form.name') %> <%= f.text_field :name %> <%= f.label :email, t('users.form.email') %> <%= f.text_field :email %> <%= f.label :username, t('users.form.username') %> <%= f.text_field :username %> <%= f.label :password, t('users.form.password') %> <%= f.password_field :password %> <%= avatar_for(@user) %> <%= f.label :avatar %> <%= f.file_field :avatar %> <%= f.submit t('users.edit.form.submit'), class: 'btn btn-large btn-primary' %> <% end %>
こんな感じのフォーム。railsの画像は画像が設定されてないときに出してる画像。
テキトウな画像を設定してみる。
おおっ。変わった。うそくせーな。
でも、画像もちゃんと:rails_root/public/system/users/avatars/:idが3桁ずつに分割されたフォルダ/画像サイズの種類/ria10.pngに保存されてる・・・。
もちろん保存先のフォルダは自由に変えられる。
これ、すごいね。
ただ、これね。テスト書いてると実行のたびに実ファイルががんがん置かれてってエライことになるので、テスト実行後に消すようにしないといけない、ということに今気づいた。
追記)書いた->Paperclip + rail3 + rspec でテストごとに作られたファイルを消す方法
追記)必須バリデーションは以下のいずれかで。
validates :avatar, :attachment_presence => true validates_with AttachmentPresenceValidator, :attributes => :avatar
- 作者: 黒田努
- 出版社/メーカー: インプレスジャパン
- 発売日: 2013/03/22
- メディア: 単行本(ソフトカバー)
- クリック: 3回
- この商品を含むブログ (6件) を見る