質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Q&A

解決済

1回答

2679閲覧

boolean型のカラムをupdateメソッドを使いfalseからtrueにする方法

so_ma

総合スコア5

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

1グッド

2クリップ

投稿2021/03/03 09:18

編集2021/03/03 23:01

前提・実現したいこと

railsでポートフォリオを作成しています。
購入の支払いをした後にuserが購入したかしていないかを判断するためにusersテーブルのboolean型のorderカラムを購入後にtrueにしようと思います

発生している問題・エラーメッセージ

購入の支払いをした後にuserが購入したかしていないかを判断するためにusersテーブルのboolean型のorderカラムを購入後にtrueにしようと思います。updateメソッドを使いupdateしたのですが、データベースに変更が反映されません。 @user.updateとしているところがうまく反映されていません。それ以外は問題なく動いています。また、エラーなどは出ていません。

該当のソースコード

ruby

1 class OrdersController < ApplicationController 2 3 def create 4 redirect_to new_card_path and return unless current_user.card.present? 5 6 @price = Price.find(params[:price_id]) 7 8 Payjp.api_key = ENV["PAYJP_SECRET_KEY"] 9 customer_token = current_user.card.customer_token 10 Payjp::Charge.create( 11 amount: @price.content, 12 customer: customer_token, 13 currency: 'jpy' 14 ) 15 16 @room = Room.find(params[:room_id]) 17 @order = Order.create(price_id: @price.id, room_id: @room.id) 18 @message = Message.create(room_id: @room.id, user_id: @room.user.id, content:"#{current_user.nickname}さんから#{@price.content}円が送られました!!", order: true) 19 @user = User.find(current_user.id) 20 @user.update(order: true) 21 ActionCable.server.broadcast 'stanp_channel', content: @message 22 23 24 end 25 26end 27

ruby

1 2class User < ApplicationRecord 3 has_one_attached :image 4 5 devise :database_authenticatable, :registerable, 6 :recoverable, :rememberable, :validatable 7 8 validates :nickname, :birthday, presence: true 9 10 validates :password, format: { with: /\A(?=.*?[a-z])(?=.*?[\d])[a-z\d]+\z/i} 11 12 with_options presence: true, format: { with: /\A[ぁ-んァ-ヶ一-龥々]+\z/ } do 13 validates :first_name 14 validates :last_name 15 end 16 17 with_options presence: true, format: {with:/\A[ァ-ヶ]+\z/} do 18 validates :first_name_katakana 19 validates :last_name_katakana 20 end 21 22 has_many :celebs, through: :rooms 23 has_many :rooms, dependent: :destroy 24 has_many :messages, dependent: :destroy 25 has_one :card, dependent: :destroy 26 has_many :likes, dependent: :destroy 27end 28 29

ruby

1create_table "users", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t| 2 t.string "email", default: "", null: false 3 t.string "encrypted_password", default: "", null: false 4 t.string "nickname", null: false 5 t.string "last_name", null: false 6 t.string "first_name", null: false 7 t.string "first_name_katakana", null: false 8 t.string "last_name_katakana", null: false 9 t.date "birthday", null: false 10 t.boolean "order", default: false 11 t.string "reset_password_token" 12 t.datetime "reset_password_sent_at" 13 t.datetime "remember_created_at" 14 t.datetime "created_at", precision: 6, null: false 15 t.datetime "updated_at", precision: 6, null: false 16 t.boolean "admin", default: false 17 t.index ["email"], name: "index_users_on_email", unique: true 18 t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true 19 end 20

試したこと

@user = User.find(current_user.id)のあとにbinding.pryを入れて確認してみたところ@userにはしっかりとuserの情報が入っていました

3: def create
4: redirect_to new_card_path and return unless current_user.card.present?
5:
6: @price = Price.find(params[:price_id])
7:
8: Payjp.api_key = ENV["PAYJP_SECRET_KEY"]
9: customer_token = current_user.card.customer_token
10: Payjp::Charge.create(
11: amount: @price.content,
12: customer: customer_token,
13: currency: 'jpy'
14: )
15:
16: @room = Room.find(params[:room_id])
17: @order = Order.create(price_id: @price.id, room_id: @room.id)
18: @message = Message.create(room_id: @room.id, user_id: @room.user.id, content:"#{current_user.nickname}さんから#{@price.content}円が送られました!!", order: true)
19: @user = User.find(current_user.id)
=> 20: binding.pry
21: @user.update(order: true)
22: ActionCable.server.broadcast 'stanp_channel', content: @message
23:
24:
25: end

[1] pry(#<OrdersController>)> @user
=> #<User id: 2, email: "q@q", nickname: "sunny1", last_name: "山田", first_name: "太郎", first_name_katakana: "タロウ", last_name_katakana: "ヤマダ", birthday: "1932-03-02", order: false, created_at: "2021-03-03 07:54:04", updated_at: "2021-03-03 07:54:04", admin: false>
[2] pry(#<OrdersController>)> @user.update(order: true)
=> false
[3] pry(#<OrdersController>)> @user.update(order: 1)
=> false
[4] pry(#<OrdersController>)> @user
=> #<User id: 2, email: "q@q", nickname: "sunny1", last_name: "山田", first_name: "太郎", first_name_katakana: "タロウ", last_name_katakana: "ヤマダ", birthday: "1932-03-02", order: true, created_at: "2021-03-03 07:54:04", updated_at: "2021-03-03 07:54:04", admin: false>

こちらがbinding.pryの結果です。
1回目のpryで@userを入力するとorderはfalseで返ってきました。
しかし2回目でupdateアクションを行うとfalseと返って来るのですが4回目ではorderがtrueとなっています。

3: def create
4: redirect_to new_card_path and return unless current_user.card.present?
5:
6: @price = Price.find(params[:price_id])
7:
8: Payjp.api_key = ENV["PAYJP_SECRET_KEY"]
9: customer_token = current_user.card.customer_token
10: Payjp::Charge.create(
11: amount: @price.content,
12: customer: customer_token,
13: currency: 'jpy'
14: )
15:
16: @room = Room.find(params[:room_id])
17: @order = Order.create(price_id: @price.id, room_id: @room.id)
18: @message = Message.create(room_id: @room.id, user_id: @room.user.id, content:"#{current_user.nickname}さんから#{@price.content}円が送られました!!", order: true)
19: @user = User.find(current_user.id)
20: @user.update(order: true)
=> 21: binding.pry
22: ActionCable.server.broadcast 'stanp_channel', content: @message
[1] pry(#<OrdersController>)> @user.errors.full_messages
=> ["パスワードは不正な値です"]

こちらがbinding.pryをして@user.errors.full_messagesを記述した際のものです

こちらが@user.update!にした時のエラー文です
https://i.gyazo.com/2cc0f56667a78a3e3f9f4bcc9bd292a9.png

自分にはこの解決方法がわかりません。
お力添えをしていただけるとありがたいです。

補足情報(FW/ツールのバージョンなど)

rails [6.0]を使っています
ここにより詳細な情報を記載してください。

sdka👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

shinoharat2

2021/03/03 14:14 編集

以下4点を質問文に追加してください。 【1】 app/models/user.rb のコード 【2】 db/schema.rb の users 部分 【3】 binding.pry で止めた状態で、「 @user.errors.full_messages 」を実行したときの結果 【4】 update ではなく update! したときの例外
so_ma

2021/03/04 01:23

コメントありがとうございます! 編集しましたのでご確認よろしくお願いします????‍♂️
guest

回答1

0

ベストアンサー

修正方法

パスワードの検証が常にONになっているのが原因です。
User クラスに以下の修正を加えてください。

app/models/user.rb

diff

1- validates :password, format: { 略 } 2+ validates :password, format: { 略 }, allow_nil: true

上記の修正により、「パスワードが nil の場合はバリデーションをスキップする」という動作になります。

解説

疑問なのですがnicknameなどにもpresence: trueをかけているのになぜpasswordのみにバリデーションをスキップするオプションヲッ加えるのでしょうか??

良い質問ですね。password カラムの動作について解説します。

例えば、以下のようなデータを新規作成したとします。

User.create!(nickname: "もっち", email: "aaa@bbb.com", password: "xyz123", ...)

そして、そのデータを find メソッドで取得します。
すると、nickname や email は保存したときの値が取得できるのですが、 password は nil になっています。

# さっき作成したデータを取得 user = User.find(さっきのid) # 普通は保存したときの値が取得できる。 user.nickname #=> "もっち" user.email #=> "aaa@bbb.com" # ただし、password は nil になる user.password #=> nil

なぜなら、DBに保存されているのは、「password」ではなく「encrypted_password」だからです。
確認してみると、encrypted_passwordカラムには、ハッシュ化されたパスワードが格納されているのがわかります。

user.encrypted_password => "...ハッシュ化されたパスワード..."

「password」は「encrypted_password」を作るための一時的な入れ物で、DBと連動しているわけではありません。
なので、DBからロードしたデータの中には「password」が含まれない(nilになる)という形です。

当然、このまま保存を実行すると、

user.nickname #=> "もっち" user.email #=> "aaa@bbb.com" user.password #=> nil

の状態でバリデーションされるため、今回のような現象に繋がります。

ちなみに、「password」をわざわざ「encrypted_password」に変換して保存するのは、セキュリティ上の理由です。

投稿2021/03/04 03:22

編集2021/03/04 04:08
shinoharat

総合スコア1676

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

shinoharat

2021/03/04 03:24

ちなみに、 @user.password #=> nil になるのは分かりますかね? 補足解説が欲しければ書きますので、またコメントください。
so_ma

2021/03/04 03:39

素早い対応ありがとうございます。 こちらの記述に直しところ無事にupdateをすることができました???? updateの際にもバリデーションがかかるため、allow_nil: trueを追加してpasswordがnilであった場合にバリデーションをスキップするという解釈で間違い無いですか?? @user.password #=> nilになるのはupdateアクションの際にpasswordを更新していないからそうなるということでしょうか??
so_ma

2021/03/04 03:45

しかし、疑問なのですがnicknameなどにもpresence: trueをかけているのになぜpasswordのみにバリデーションをスキップするオプションヲッ加えるのでしょうか??
shinoharat

2021/03/04 04:10 編集

> updateの際にもバリデーションがかかるため、allow_nil: trueを追加してpasswordがnilであった場合にバリデーションをスキップするという解釈で間違い無いですか?? その解釈で間違いないです????‍♂️ > @user.password #=> nilになるのはupdateアクションの際にpasswordを更新していないからそうなるということでしょうか?? > しかし、疑問なのですがnicknameなどにもpresence: trueをかけているのになぜpasswordのみにバリデーションをスキップするオプションヲッ加えるのでしょうか?? 回答欄に詳しい解説を追記しましたので、またご確認ください。
so_ma

2021/03/04 05:18

とてもわかりやすい解説ありがとうございました! これでやっと次に進めそうです!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問