railsの関連付け・外部キーでハマった結果、deviseの奥深さ…というか基礎を学んだ話
はじめまして、こういった記事を書くのは初めてになります。
おてやわらかにお願いします!
記事の内容・前提
- ruby2.7, rails6.0で個人学習用にアプリを開発中
- userモデル(devise)とroomモデルを関連付けたのに、外部キーroom_idに値が入らない
- 問題を解決したところ、知らなかったdeviseの仕様もついでに学べた
トラブっていたこと
userモデル(devise)の外部キーroom_idに値が入らない。
実現させたいのは、userがroomを作るとき、userの外部キーroom_idに、作ったroomのidを入れること。
/models/user.rb
belongs_to :room, optional: true
validates :name, presence: true, length: { in: 2..40 }
validates :password, presence: true, length: { in: 6..30 }
validates :email, ...(略)
/models/room.rb
has_many :users
モデル間の関連付けは問題ないはず…
/controllers/rooms_controller.rb
def create
@room = Room.new(room_params)
if @room.save
@user.update(room_id: @room.id)
redirect_to room_url(token: @room.token)
else
redirect_to root_path
end
end
4行目の@user.update(room_id: @room.id)
で外部キーにidが入りそうなのに結果は×。
ログを見ると
↳ app/controllers/rooms_controller.rb:18:in `create'
(0.6ms) ROLLBACK
ロールバック!?
そんな悪いことしたでしょうか(汗)
ロールバックの原因
先に原因をお伝えします。
原因は「userモデルで設定されているバリデーションが発動したから」でした。
解決した方法
まず、先ほどの@user.update(room_id: @room.id)
を
4行目の@user.update!(room_id: @room.id)
に変更しました。
ロールバックの心当たりがなかったので、update!
にして、エラー内容を把握しようと考えたからです。
ビックリをつけると(update
からupdate!
)、何が変わるのか?
以下の記事から学ばせていただきました。引用します
メソッドを実行した結果、バリデーションに失敗したとき(DBに保存できなかったとき)に例外を発生させる。
Ruby や Rails でよく見る、メソッド名の後ろのびっくりマーク(感嘆符)の意味
話を戻します。
update!
で試したところ、エラーの表示が!
内容は…
「…バリデーション?パスワード?どゆこと???」
とりあえず、userモデルのpasswordのバリデーションをコメントアウトしました。
/models/user.rb
# validates :password, presence: true, length: { in: 6..30 }
再度update!
で試すと…
エラーなく通りました。
なんで?
(このあと、原因を考えたのですが、userモデルにpasswordカラムがないので(代わりにencrypted_passwordカラムがある)、user.rbにpasswordのバリデーションがあるのはおかしいから、だと見当をつけました)
・・・
ひとまず、当初の問題、「userモデル(devise)の外部キーroom_idに値が入らない」は打開策が見つかりました。
生じた疑問とその答え
当初の問題はクリアできました。
でも新たな疑問が。
さっきpasswordのバリデーションをコメントアウトしたわけですが、そのままuserの登録をパスワード3文字で試してみると…
なんで???
deviseはどこでpasswordのバリデーションをしてるのか?
完全に疑問です。
・・・
ググったらすぐにわかりました。引用します。
deviseの場合、パスワードはデフォルトで「6〜128文字」で制限がかけられています。
こちらは、「config/initializer/devise.rb」にて変更できます
Railsのdeviseでモデル作成後に実行したい3つのバリデーションは?
なるほど…。
そもそもdeviseはここでpasswordのバリデーションを設定しているんですね。あとemailも。全然知りませんでした。
つまり、冒頭に/models/user.rb
のコードを載せましたが、
/models/user.rb
validates :name, presence: true, length: { in: 2..40 }
validates :password, presence: true, length: { in: 6..30 } #いらない
validates :email, ...(略) #いらない
ということですねおそらく。おそらくですが。
今回の学び
- deviseで作ったモデルのemailとpasswordには
config/initializer/devise.rb
にデフォルトでバリデーションが設定されている
転職を考えている方へ
「転職ドラフト」というサービスを使って、企業から指名を受けてみませんか?
実務1-2年目でも、うまくいけば転職ドラフトで年収数百万UPできるようです(ググると記事が見つかるはず)
登録時に次の紹介コードを入れて、その後レジュメ審査が通過すると、もれなくAmazonギフト券3000円分などのプレゼントがもらえます。
気になっている方はぜひ使ってみてください!
紹介コード:HJGJ
転職ドラフト
Discussion