Rails 4.1 で CarrierWave を使う


[PaperClip](http://qiita.com/akishin/items/8bc2196500781ded2c0d "Rails 4.1 で PaperClip を使う") を試した時と同等のサンプルを CarrierWave で作ってみた。

## 公式

carrierwaveuploader/carrierwave
https://github.com/carrierwaveuploader/carrierwave

Home · carrierwaveuploader/carrierwave Wiki
https://github.com/carrierwaveuploader/carrierwave/wiki

## 試した環境

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

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 'carrierwave'
```

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

適当な scaffold を生成。

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

続いて uploader を生成。

```shell-session
% ./bin/rails g uploader Avatar
```

このジェネレータを実行する事で carrierwave のアップロード用設定を定義した Uploader クラスが `app/uploaders` ディレクトリ以下に生成される。

生成された avatar_uploader.rb はコメント部分を除くと以下のような内容。

```ruby:app/uploaders/avatar_uploader.rb
class AvatarUploader < CarrierWave::Uploader::Base
  storage :file

  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end
end
```

その他のオプション等はコメントで記載されている。

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

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

以下のような内容のファイルが生成された。

```ruby:db/migrate/2014XXXXXXXXXX_add_avatar_to_users.rb
class AddAvatarToUsers < ActiveRecord::Migration
  def change
    add_column :users, :avatar, :string
  end
end
```

特に変更する必要はないのでそのままマイグレーション実行。

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

User モデルを以下のように変更。
先ほど生成した `AvatarUploader` を使うように設定している。

```ruby:app/models/user.rb
class User < ActiveRecord::Base
  mount_uploader :avatar, AvatarUploader
end
```

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

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

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
└── uploads
    ├── tmp
    └── user
        └── avatar
            └── 1
                └── example_image1.jpg
```

アップロードしたファイルの情報のうちファイル名が DB のカラムに保存される模様。

```
sqlite> select * from users;
1|Test User|testtest|2014-11-30 04:59:55.384606|2014-11-30 04:59:55.384606|example_image1.jpg
```

Model 経由でファイルにアクセスする際にはこのカラムが Uploader クラスのオブジェクトとなっているので、以下のようにいろいろと便利なメソッドが使用できる。

```ruby
> u = User.find(1)
> u.avatar.class
=> AvatarUploader
> u.avatar
=> #<AvatarUploader:0x007ff57aa78308 @model=#<User id: 1, name: "Test User", password: "testtest", created_at: "2014-11-30 04:59:55", updated_at: "2014-11-30 04:59:55", avatar: "example_image1.jpg">, @mounted_as=:avatar, @storage=#<CarrierWave::Storage::File:0x007ff57aa781a0 @uploader=#<AvatarUploader:0x007ff57aa78308 ...>>, @file=#<CarrierWave::SanitizedFile:0x007ff57aa6b630 @file="/home/akishin/src/rails/uploader/public/uploads/user/avatar/1/example_image1.jpg", @original_filename=nil, @content_type=nil>, @versions={}>
> u.avatar.url
=> "/uploads/user/avatar/1/example_image1.jpg"
> u.avatar.current_path
=> "/home/akishin/src/rails/uploader/public/uploads/user/avatar/1/example_image1.jpg"
```

CarrierWave では Paperclip と異なり、アップロード時に自動的に縮小画像やサムネイルを生成したりはしない。
サムネイル生成などを行いたい場合はこの辺りを見て設定すればいい。

Adding versions
https://github.com/carrierwaveuploader/carrierwave#adding-versions

機能も多いがかなりドキュメントが充実しているので特に困る事も無さそう。

## 関連

Rails 4.1 で Paperclip を使う - Qiita http://qiita.com/akishin/items/8bc2196500781ded2c0d

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

## 参考

ASCIIcasts - “Episode 253 - CarrierWaveでファイルのアップロード”
http://ja.asciicasts.com/episodes/253-carrierwave-file-uploads

Rails 超お手軽な画像アップローダー CarrierWave の使い方 | Workabroad.jp
http://www.workabroad.jp/tech/1118

carrierwave + rails 4.1 画像アップローダー - 酒と泪とRubyとRailsと
http://morizyun.github.io/blog/carrierwave-image-uploader-rails/

carrierwave 使い方 - Qiita
http://qiita.com/dahugani/items/39b888aa64f482ff434a

AWS - Rails+Carrierwave+fog+Heroku+S3でハマったメモ - Qiita
http://qiita.com/kimihito_/items/3ff9c0c4407447ee3ab3