Rails 4.1 で Paperclip を使う


Rails でファイルアップロードを簡単に実装できる Paperclip を試してみた時のメモ。
画像以外も上げられるが、機能的には画像ファイルに特化してる模様。

## 公式

thoughtbot/paperclip
https://github.com/thoughtbot/paperclip

## 必要なソフトウェア

- Ruby 1.9.2 以降
- Rails 3.0 以降
- ImageMagick
- file コマンド

## 試した環境

```shell-session
% cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.04
DISTRIB_CODENAME=trusty
DISTRIB_DESCRIPTION="Ubuntu 14.04.1 LTS"
```

動作には ImageMagick の convert コマンドが必要との事なので確認。
既に入れてあった。

```shell-session
% convert --version
Version: ImageMagick 6.7.7-10 2014-03-06 Q16 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2012 ImageMagick Studio LLC
Features: OpenMP
```

また、file コマンドも必要との事なので確認。

```shell-session
% file --version
file-5.14
```

Ruby 周りは以下。

```shell-session
% ./bin/rake about 
About your application's environment
Ruby version              2.1.3-p242 (x86_64-linux)
RubyGems version          2.2.2
Rack version              1.5
Rails version             4.1.8
JavaScript Runtime        Node.js (V8)
Active Record version     4.1.8
Action Pack version       4.1.8
Action View version       4.1.8
Action Mailer version     4.1.8
Active Support version    4.1.8
```

## 使ってみる

適当なプロジェクトを作成。

```shell-session
% rails new uploader --skip-bundle && cd uploader && bundle install --path=vendor/bundle
```

Gemfile に以下を追記。

```ruby:Gemfile
gem 'paperclip'
```

追記したら再度 `bundle install` を実行。
paperclip 4.2.0 がインストールされた。

適当な scaffold を生成。

```shell-session
% ./bin/rails g scaffold user name:string password:string
```

生成された User モデルを以下のように変更。
内容は公式の Quick Start のものそのまま。

```ruby:app/models/user.rb
class User < ActiveRecord::Base
  has_attached_file :avatar, :styles => { :medium => "300x300>", :thumb => "100x100>" }, :default_url => "/images/:style/missing.png"
  validates_attachment_content_type :avatar, :content_type => /\Aimage\/.*\Z/
end

```

`has_attached_file` に指定可能なオプションについては以下を参照。

Module: Paperclip::ClassMethods ? Documentation for paperclip (4.2.0)
http://www.rubydoc.info/gems/paperclip/Paperclip/ClassMethods


`validates_attachment_content_type` は必須のようで、指定しないと `Paperclip::Errors::MissingRequiredValidatorError` が発生する。
画像以外のファイルを上げたい場合は `content_type` を変更すればいい模様。
例えば text ファイルを上げたければ以下のように変更すればいい。

```ruby
validates_attachment_content_type :avatar, :content_type => /\Atext\/.*\Z/
```

アップロードファイル用カラムの為のマイグレーションファイルを作成。

```shell-session
% ./bin/rails g migration add_avatar_to_users
```

生成されたマイグレーションファイルを以下のように変更。

```ruby:db/migrate/2014XXXXXXXXXX_add_avatar_to_users.rb
class AddAvatarToUsers < ActiveRecord::Migration
  def self.up
    add_attachment :users, :avatar
  end

  def self.down
    remove_attachment :users, :avatar
  end
end
```

マイグレーション実行。

```shell-session
% ./bin/rake db:create db:migrate
```

以下のようなテーブルが作成された。

```sql
CREATE TABLE "users" (
    "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
    ,"name" VARCHAR (255)
    ,"password" VARCHAR (255)
    ,"created_at" datetime
    ,"updated_at" datetime
    ,"avatar_file_name" VARCHAR (255)
    ,"avatar_content_type" VARCHAR (255)
    ,"avatar_file_size" INTEGER
    ,"avatar_updated_at" datetime
);
```

View の `form_for` 内の適当な位置に `file_field` を追加する。
Rails4 なので `:multipart => true` は省略。

```erb:app/views/users/_form.html.erb 
<div class="field">
  <%= f.label :avatar %><br>
  <%= f.file_field :avatar %>
</div>
```

Controller で Strong Parameters が追加したパラメータを通すように `permit` に追加。

```ruby:app/controllers/users_controller.rb
def user_params
  params.require(:user).permit(:name, :password, :avatar)
end
```

これで `rails server` で起動してブラウザからアクセスするとファイルアップロード出来るようになっている。
アップロードしたファイルは以下に保存されている。

デフォルトでアップロード時に縮小画像やサムネイルを生成しているっぽい。

```shell-session
public
└── system
    └── users
        └── avatars
            └── 000
                └── 000
                    └── 001
                        ├── medium
                        │   └── example_image1.jpg
                        ├── original
                        │   └── example_image1.jpg
                        └── thumb
                             └── example_image1.jpg
```

テキストファイルをアップロードした場合も ImageMagick での処理は通るらしく同様のディレクトリ構成でファイルが保存された。
その場合 original 以外のディレクトリ内のファイルは以下のようなものだった。

```
# ImageMagick pixel enumeration: 77,100,65535,srgba
0,0: (65535,65535,65535,65535)  #FFFFFFFFFFFF  white
1,0: (65535,65535,65535,65535)  #FFFFFFFFFFFF  white
2,0: (65535,65535,65535,65535)  #FFFFFFFFFFFF  white
3,0: (65535,65535,65535,65535)  #FFFFFFFFFFFF  white
4,0: (65535,65535,65535,65535)  #FFFFFFFFFFFF  white
5,0: (65535,65535,65535,65535)  #FFFFFFFFFFFF  white
・
・
・
```

ここでは試していないが、他にも以下の Validator も提供されている。

- validates_attachment_presence
- validates_attachment_size

## 関連

Rails 4.1 で CarrierWave を使う - Qiita http://qiita.com/akishin/items/46b2e239cf4190171da8

Rails 4.1 で Dragonfly を使う - Qiita http://qiita.com/akishin/items/0fc236feb86092fe98c7

## 参考

134 Paperclip - RailsCasts
http://railscasts.com/episodes/134-paperclip

Paperclip と CarrierWave を結構マジメに比較してみた - 彼女からは、おいちゃんと呼ばれています
http://blog.inouetakuya.info/entry/20131014/1381749488

Rails3+paperclipでファイルアップロード - リア充爆発日記
http://d.hatena.ne.jp/ria10/20121213/1355392305

[Ruby on Rails]paperclipでつくるS3への画像保存アプリ ｜ Developers.IO
http://dev.classmethod.jp/server-side/ruby-on-rails/ruby-on-railspaperclip_s3_image_store/

RailsでPaperclipを使ってAmazon S3に画像を保存する | aguuu
http://www.aguuu.com/archives/2012/12/paperclip/

RailsのファイルアップロードgemのPaperclipの使い方 - Rails Webook
http://ruby-rails.hatenadiary.com/entry/20140716/1405443484