deviseとActive Storage を使ってavatar（アイコン)登録する

## Active Storageの場合 (Rails 5.2以降の場合）

アクティブストレージは保存場所を信頼性の高いamazon, google, microsoftが提供するクラウドに保存できる。またバックアップもできるので、データが消えた場合などに非常に重宝されます。

設定方法も非常に簡単です。

[概要](https://railsguides.jp/active_storage_overview.html)
[Active StorageによるRails ファイルアップロード](https://qiita.com/ebi_ebi/items/260be781987284bf3866)
[Active Strageを使用してユーザーのアバターを登録、表示する](https://re-engines.com/2018/03/12/active-strage%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%A6%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%81%AE%E3%82%A2%E3%83%90%E3%82%BF%E3%83%BC%E3%82%92%E7%99%BB%E9%8C%B2%E3%80%81%E8%A1%A8%E7%A4%BA/)
[参考になるページ](http://digital-tree.xyz/blogs/813)
[【Rails 5.2】 Active Storageの使い方](https://qiita.com/hmmrjn/items/7cc5e5348755c517458a)

```:ターミナル
$ rails active_storage:install
$ bundle exec rake db:migrate
```
rails active_storage:installコマンドを実行すると、active_storage_blobs と active_storage_attachmentsテーブルが生成されるのでこちらをモデルに反映させるためrails db:migrateする

作成されたテーブルは下記の役割となります。

|テーブル  |機能  |
|---|---|
|active_storage_blobs  |アバター画像の保存先  |
|active_storage_attachments  |userとavatorの中間テーブル  |

ローカル環境、テスト環境、本番環境で保存先を変更する。
storage.ymlで設定を変えていく

```ruby:config/storage.yml
test:
  service: Disk
  root: <%= Rails.root.join("tmp/storage") %>

local:
  service: Disk
  root: <%= Rails.root.join("storage") %>

# Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key)
# amazon:
#   service: S3
#   access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %>
#   secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %>
#   region: us-east-1
#   bucket: your_own_bucket

# Remember not to checkin your GCS keyfile to a repository
# google:
#   service: GCS
#   project: your_project
#   credentials: <%= Rails.root.join("path/to/gcs.keyfile") %>
#   bucket: your_own_bucket

# Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key)
# microsoft:
#   service: AzureStorage
#   storage_account_name: your_account_name
#   storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %>
#   container: your_container_name

# mirror:
#   service: Mirror
#   primary: local
#   mirrors: [ amazon, google, microsoft ]
```

すでにamazonの記述はあります。なので,amazonのs3で保存する場合はコメントアウトを解除して下記のようにします。


```ruby:config/storage.yml
test:
  service: Disk
  root: <%= Rails.root.join("tmp/storage") %>

local:
  service: Disk
  root: <%= Rails.root.join("storage") %>

amazon:
  service: S3
  access_key_id: <%= Rails.application.credentials.dig(:aws, "YOUR ACCESS_KEY_ID") %>
  secret_access_key: <%= Rails.application.credentials.dig(:aws, "YOUR SECRET_ACCESS_KEY") %>
  region: ap-northeast-1 # 東京の場合（海外の場合異なります）
  bucket: バケット名

```

```ruby:config/environments/production.rb
# :localから:amazonに変更することで、先ほど定義したamazon:を読み込みさせる。
config.active_storage.service = :amazon
```

AWS用のGemを追加します

```ruby:Gemfile
gem 'aws-sdk-s3', require: false
```

userモデルとavatorを紐づける

```ruby:user.rb
class User < ApplicationRecord
  #Include default devise modules. Others available are:
  #:confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  has_one_attached :avatar # 追加
end
```
このアクセサに、Active Strageがファイルをアタッチしてくれます。
なお、レコードとファイルが1対1の場合は has_one_attached ですが、1対多の場合は has_many_attached になります。

```haml:form
= f.file_field :avatar
```

これで登録可能です。

## 編集の場合

今回はgem "devise"を利用してアイコンを登録する場合です。

deviseのparamsを指定するために、application_controllerでaccount_updateの記述を追加します

```ruby:application_controller.rb
  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [ :avatar] )
    devise_parameter_sanitizer.permit(:account_update, keys: [ :avatar])
  end
```

これでparamsにavatarが読み取れます。
つづいて、active_strageで保存する場合、

```
親要素.イメージ名.attach(params[:key]
```
とする必要があります。
例えば,既存のuserにavatarを付与するには

```ruby:
User.avatar.attach(params[:avatar])
```
とします。
.attachメソッドで追加/更新しなければいけないのがポイントです。
ですから、通常通りupdateするだけでは更新されません。
update処理に.attachを追加します。今回はdeviseということなので、deviseのregistration_controller.rbに処理を追加します。コメントアウトを解除して、下記の処理にします。


```ruby:registration_controller.rb
  def update
    super
    if account_update_params[:avatar].present?
      resource.avatar.attach(account_update_params[:avatar])    
    end
  end
```

これでavatarが付与/更新されます。

## 参考資料


[[Rails][devise] devise + active_recordで画像を編集する](https://qiita.com/after4649/items/6f1d80b21287e09a7477)
[バリデーションの設定](https://qiita.com/yamamoto11081/items/7211f6d3a55d8bd45ee4)