[学習用]Rails5：CarrierWaveで画像投稿＋rmagickでサムネイル保存＋画像名ランダム化

うっかり忘れたので構築した手順を忘れない様にメモ。
※ローカルテスト用。Herokuには保存できないので、AWSのS3に保存するときは
　保存先を違うものに変更する必要がある。


#scaffold で一括作成
```
$ rails g scaffold shop title:string content:text name:string cat_id:integer user_id:integer image:string
```

まず、scaffold で一括作成。

## ハマったポイント
このときimage:string　も一緒に作ってしまう。
ここを忘れてて、画像が登録されないerrorに悩まされる。

###もし追加し忘れたら
```
$ rails g migration add_image_column_to_shops image:string
$ rails db:migrate
```
これで大丈夫。

#Gem　CarrierWaveの追加
```Gemfile
gem 'carrierwave'
```
Gemfile に上記を追加して

```
$ bundle
```

#アップローダークラス生成
```
$ rails g uploader image
```
app/uploader/image_uploader.rb が作成される

##CarrierWave編集
```app/uploaders/image_uploader.rb
class ImageUploader < CarrierWave::Uploader::Base
  storage :file
  # storage :fog

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

  def extension_whitelist
    %w(jpg jpeg gif png)
  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
```

###はまったポイント
"#{Time.zone.now.strftime('%Y%m%d%H%M%S')}.jpg" if original_filename.present?
タイムゾーンにするとリサイズ時にエラーが出てサイズの変更ができなくなる。
エラー名が全然違うので、全くわからなかった。
RMagick入ってないよとかMiniMagick入ってないよとかそんなerrorが出てテンパる。


##追加
```/app/models/shop.rb
class Shop < ApplicationRecord
  mount_uploader :image, ImageUploader
end
```

#パラメータの確認
```/app/controllers/posts_controller.rb
  private
    # Use callbacks to share common setup or constraints between actions.
    def set_shop
      @shop = Shop.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def shop_params
      params.require(:shop).permit(:title, :content, :cat_id, :name, :user_id, :image)
    end
```

image をscaffoldより後から追加したなら　:imageを追加する。
image　をscaffoldで追加したなら入っているか確認する。

#画像が表示できる様にする
##画像を登録
```/app/views/_form.html.erb

  <%= form.label :image %>
  <%= form.file_field :image %>

```
変更、新規、編集の時に追加できるように。


#表示側の追加
```/app/views/show.html.erb
<% if @shop.image? %>
  <%= image_tag @shop.image.url %>
<% end %>
```

#画像のリサイズ
```Gemfile
gem 'rmagick'
```

```
$ bundle
```

##CarrierWave編集
```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

  # ファイルサイズに制限をつける
  def size_range
    1..5.megabytes
  end

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

  # サムネイル保存する
  version :thumb do
    process :resize_to_limit => [320, 320]
  end

  # 保存形式
  process :convert => 'jpg'

  def extension_whitelist
    %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
```

##Viewにサムネイル追加
```/app/views/show.html.erb
<% if @shop.image? %>
  <%= image_tag @shop.image.url %>
<% end %>

<%= image_tag @shop.image.url(:thumb) %>
```

これで640画像と320のサムネイル画像が表示される
これで忘れても大丈夫なはず。


参考にしたサイト
https://nyoken.com/rails-carrierwave