【Rails】UserテーブルをUPDATEした時にROLLBACKした原因と解決方法

# 今回の経緯
Userテーブルのemailの値とimageファイルの変更に失敗する。
次の画像は、実際にUserテーブルを更新した際に上手く動作しなかった時の映像です。
![testdouga.mov.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/398832/8f3a0466-be40-ef5b-7368-d449bd0d7e60.gif)


ターミナルは次のような処理が走っています。

```rb
Started PATCH "/users/71" for ::1 at 2019-06-15 19:54:55 +0900
Processing by UsersController#update as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"a2Ma+qZALw6OESo45mSJ1hWQv18YyK5h86pkt6edPFgQzfEyI8w9k5ILpTThxyFIZ4vOOCavP+Kn3C17SgZsgw==", "user"=>{"email"=>"aaa@bbb.ccc", "image"=>#<ActionDispatch::Http::UploadedFile:0x00007fba4aa027e0 @tempfile=#<Tempfile:/var/folders/v1/rm2pdthd0jg_brcdz1d64ht40000gn/T/RackMultipart20190615-10003-1vnlx4b.JPG>, @original_filename="RIMG0005.JPG", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"user[image]\"; filename=\"RIMG0005.JPG\"\r\nContent-Type: image/jpeg\r\n">}, "commit"=>"確定", "id"=>"71"}
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 71], ["LIMIT", 1]]
  ↳ app/controllers/users_controller.rb:53
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 71], ["LIMIT", 1]]
  ↳ app/helpers/sessions_helper.rb:3
   (0.1ms)  BEGIN
  ↳ app/controllers/users_controller.rb:28
  User Exists (0.3ms)  SELECT  1 AS one FROM "users" WHERE "users"."email" = $1 AND "users"."id" != $2 LIMIT $3  [["email", "aaa@bbb.ccc"], ["id", 71], ["LIMIT", 1]]
  ↳ app/controllers/users_controller.rb:28
   (0.2ms)  ROLLBACK
  ↳ app/controllers/users_controller.rb:28
Redirected to http://localhost:3000/users/71
Completed 302 Found in 765ms (ActiveRecord: 1.0ms)
```

# 原因
編集時にpasswordの値を渡しておらず、passwordのバリデーション`length: { minimum: 6 }`にひっかかっていた。

# 解決方法
(1)パスワードのバリデーションに条件を加える。`例）unless: :password_digest`
(2)editを行うViewファイルに、hidden属性としてpasswordの値を渡す。
(3)そもそも実際のサービスでは、プロフィール編集時にpassword入力させる必要がある。（今回はさせていなかった）

# 解決に向けて試した事

ControllerのUpdate処理の前に、binding.pryを入れて値の確認（byebugでも可）

```rb
  before_action :set_user,only:[:update]

  def update
    binding.pry
    if @user.id != current_user.id
      redirect_to root_path, notice: '他のアカウントから変更することはできません'
    elsif @user.update(user_params)
      redirect_to user_path(current_user.id), notice: 'プロフィール画像を更新しました'
    else
      redirect_to user_path(current_user.id), notice: 'プロフィール画像の更新に失敗しました'
    end
  end

  private

  def set_user
    @user = User.find(params[:id])
  end

  def user_params
    params.require(:user).permit(:name,:email,:password,:password_confirmation,:image,:image_cache)
  end

```

もう一度binding.pryが発火するまで操作する。
ターミナルでparamsを確認する。

```rb
pry(#<UsersController>)> params
=> <ActionController::Parameters {
  "utf8"=>"✓", 
  "_method"=>"patch", 
  "authenticity_token"=>"AxLyzK8R83er9WZjN3oYG72+146wLjSBytZ3TIc7G814vBkEKp3h6rfv6W8w2bCFz6Wm6Y5JpQKeoD6AaqBLFg==", 
  "user"=><ActionController::Parameters {
    "email"=>"aaa@bbb.ccc", 
    "image"=>#<ActionDispatch::Http::UploadedFile:0x00007fba4861fad0 @tempfile=# 
    <Tempfile:/var/folders/v1/rm2pdthd0jg_brcdz1d64ht40000gn/T/RackMultipart20190615-10003-12vzwe0.JPG>, 
    @original_filename="RIMG0005.JPG", 
    @content_type="image/jpeg", 
    @headers="Content-Disposition: form-data; name=\"user[image]\"; filename=\"RIMG0005.JPG\"\r\nContent-Type: image/jpeg\r\n">
  } permitted: false>, 
  "commit"=>"確定", 
  "controller"=>"users", 
  "action"=>"update", 
  "id"=>"71"
} permitted: false>
```
渡した値は問題無い事が確認できた。（と思っていた）
次にUpdateを実行してみる。

```rb
pry(#<UsersController>)> @user.update(user_params)
   (0.3ms)  BEGIN
  ↳ (pry):8
  User Exists (1.7ms)  SELECT  1 AS one FROM "users" WHERE "users"."email" = $1 AND "users"."id" != $2 LIMIT $3  [["email", "aaa@bbb.ccc"], ["id", 71], ["LIMIT", 1]]
  ↳ (pry):8
   (0.3ms)  ROLLBACK
  ↳ (pry):8
=> false
pry(#<UsersController>)> 
```
やはりROLLBACKした。
次にバリデーション例外が発生していないか確認する。

```rb
pry(#<UsersController>)> @user.errors
=> #<ActiveModel::Errors:0x00007fba4ea78220
 @base=
  #<User:0x00007fba48b5dda8
   id: 71,
   name: "test",
   email: "aaa@bbb.ccc",
   password_digest: "$2a$10$xjr3B5Ch6TeV2o5P/96uRuenFEk3XxGDQ74s97rHubxcry4EKQETq",
   created_at: Sat, 15 Jun 2019 19:36:55 JST +09:00,
   updated_at: Sat, 15 Jun 2019 19:36:55 JST +09:00,
   image: nil>,
 @details={:password=>[{:error=>:blank}, {:error=>:too_short, :count=>6}]},
 @messages={:password=>["を入力してください", "は6文字以上で入力してください"]}>
pry(#<UsersController>)> @user.errors.full_messages
=> ["パスワードを入力してください", "パスワードは6文字以上で入力してください"]
```
パスワードの値が無い事が原因だと判明した。

ちなみに`image: nil`と出ているが、実際には値が存在することが確認できる。

```rb
[9] pry(#<UsersController>)> @user.image
=> #<ImageUploader:0x00007fba4ea53998
 @cache_id="1560597767-10003-0007-8003",
 @cache_storage=#<CarrierWave::Storage::File:0x00007fba4879fa90 @cache_called=nil, @uploader=#<ImageUploader:0x00007fba4ea53998 ...>>,
 @file=
  #<CarrierWave::SanitizedFile:0x00007fba4ea521b0
   @content=nil,
   @content_type="image/jpeg",
   @file="/Users/apple/workspace/insta_clone/public/uploads/tmp/1560597767-10003-0007-8003/RIMG0005.JPG",
   @original_filename="RIMG0005.JPG">,
 @filename="RIMG0005.JPG",
 @format=nil,
 @model=
```

以上です。