【Rails】CarrierWaveとrmagickでプロフィール画像を設定できるようにする

##CarrierWaveで画像のアップロード機能を実装する
今回はユーザーテーブルにプロフィール画像を設定できるようにします。
###1. モデルに画像アップロード用のカラムを設定する
userモデルに画像をアップロードするためのimageカラムを追加します。

```
$ rails g migration add_image_column_to_users image:string
```

マイグレーションファイルの内容を適用します。

```
$ rails db:migration
```

もしすでにデータベース内にimageカラムを持っていないユーザーデータが存在しているなら、データベースの中身を一度リセットする必要があります。

```
$ rake db:migrate:reset
```

###2. Gemfileにcarrierwaveを追加してbundle installを実行

```:Gemfile
gem 'carrierwave'
```

```
$ bundle install
```

サーバーの再起動も忘れないように、このタイミングで。（基本いつでも大丈夫）

```
rails s
```

###3. rails g uploader imageで画像のアップローダークラスを作成
```
$ rails g uploader image
```
これで画像をアップロードできるようになります。

###4. アップローダを実装したいクラスに以下のコードを追加
```ruby:/app/models/user.rb
mount_uploader :image, ImageUploader
```

###5. Strong Parameterにimageカラムを追加
```ruby:/app/controllers/users_controller.rb
def user_params
  params.require(:user).permit(:name, :email, :image)
end
```
これで画像をアップロードする準備が整いました、あとはviewを記述するだけです。

###6. 画像の表示・投稿するためのviewを記述
画像表示するためのview

```ruby:/app/views/users/show.html.erb
<% if @user.image? %>                                                              
  <%= image_tag @user.image.url %>
<% end %>
```

画像を投稿するためのview

```ruby:/app/views/users/new.html.erb
<%= f.label :image %>
<%= f.file_field :image %>
```

これで画像の表示・投稿機能が完成しました！
アップロードした画像はpublicフォルダ内に格納されていました。しかしこのままではアップロードしたときの画像名・大きさでフォルダ内に保存されるので、画像の加工を行うgemのrmagickを利用します。

##rmagicで画像の加工を行う

rmagickのgemをインストールするにはimageMagickがインストールされていないといけないそうです。

imageMagickがインストールされているかは以下のコマンドで確認できます。

```
$ convert -version
```

もしインストールされていなかったらimageMagickをインストールしてください。Macの場合はbrewを使えばインストールできるそうです。

```
$ brew install imagemagick@6
```

###1. Gemfileにrmagickを追加してbundle installを実行します

```:Gemfile
gem 'rmagick'                                                                      
```

```
$ bundle install
```

サーバーの再起動も忘れないでね

###2. image_uploader.rbで設定を記述する
画像をどのような形式に加工するかは、/app/uploaders/image_uploader.rbで設定できます。

デフォルトでは以下のようになっています、このファイルを編集していきます。

```ruby:/app/uploaders/image_uploader.rb
class ImageUploader < CarrierWave::Uploader::Base
  # Include RMagick or MiniMagick support:
  # include CarrierWave::RMagick
  # include CarrierWave::MiniMagick

  # Choose what kind of storage to use for this uploader:
  storage :file
  # storage :fog

  # Override the directory where uploaded files will be stored.
  # This is a sensible default for uploaders that are meant to be mounted:
  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

  # Provide a default URL as a default if there hasn't been a file uploaded:
  # def default_url(*args)
  #   # For Rails 3.1+ asset pipeline compatibility:
  #   # ActionController::Base.helpers.asset_path("fallback/" + [version_name, "default.png"].compact.join('_'))
  #
  #   "/images/fallback/" + [version_name, "default.png"].compact.join('_')
  # end

  # Process files as they are uploaded:
  # process scale: [200, 300]
  #
  # def scale(width, height)
  #   # do something
  # end

  # Create different versions of your uploaded files:
  # version :thumb do
  #   process resize_to_fit: [50, 50]
  # end

  # Add a white list of extensions which are allowed to be uploaded.
  # For images you might use something like this:
  # def extension_whitelist
  #   %w(jpg jpeg gif png)
  # end

  # Override the filename of the uploaded files:
  # Avoid using model.id or version_name here, see uploader/store.rb for details.
  # def filename
  #   "something.jpg" if original_filename
  # end
end
```

変更を加えたファイルはこのようになりました。

```ruby:/app/uploaders/image_uploader.rb
class ImageUploader < CarrierWave::Uploader::Base  

  # リサイズしたり画像形式を変更するのに必要
  include CarrierWave::RMagick

  # 画像の上限を640x480にする
  process :resize_to_limit => [640, 480]

  # 保存形式をJPGにする
  process :convert => 'jpg'

  # サムネイルを生成する設定
  version :thumb do
    process :resize_to_limit => [300, 300]
  end

  version :thumb100 do
    process :resize_to_limit => [100, 100]
  end

  version :thumb30 do
    process :resize_to_limit => [30, 30]
  end

  # jpg,jpeg,gif,pngしか受け付けない
  def extension_white_list
    %w(jpg jpeg gif png)
  end

  # 拡張子が同じでないとGIFをJPGとかにコンバートできないので、ファイル名を変更
  def filename
    super.chomp(File.extname(super)) + '.jpg' if original_filename.present?
  end

  # ファイル名を日付にするとタイミングのせいでサムネイル名がずれる
  #ファイル名はランダムで一意になる
  def filename
    "#{secure_token}.#{file.extension}" if original_filename.present?
  end

  protected
  def secure_token
    var = :"@#{mounted_as}_secure_token"
    model.instance_variable_get(var) or model.instance_variable_set(var, SecureRandom.uuid)
  end

end

```

これで完了です！


###参考
https://pg-happy.jp/carrierwave-rmagic-uploader.html
https://nyoken.com/rails-carrierwave

image_uploader.rbについて
http://www.workabroad.jp/tech/1118
https://qiita.com/tackey/items/ba68ca8489500b7cb739