概要
ユーザー登録とプロフィールをさせる時に、ウィザード形式でフォームを作成。
プロフィールに画像を保存したかったが上手くいかなかったため備忘録として記載。
※検索しても同じ状況の方がいなかったので役に立てばと思います。
ウィザード形式とは何か?という方はこちらを参考にしてください
内容
開発環境
MacOS Catalina 10.15.6
Rails 6.0.0
Ruby 2.6.5
テーブル構成
deviseを使ってユーザー登録をさせようとしています。
userテーブルはnicknameのみ追加。
profileテーブルにはtwitterのリンクなど記載。
profileテーブルにactive_strageで画像を保存したい。
ウィザード形式を実装
ここらへんの機能の実装に関しては
こちらの記事がかなり近いので参考にしました。
問題点
ウィザード形式で、画像以外はしっかり保存できたけど、画像は保存されない。
class Users::RegistrationsController < Devise::RegistrationsController
def create
@user = User.new(sign_up_params)
unless @user.valid?
render :new and return
end
session["devise.regist_data"] = {user: @user.attributes}
session["devise.regist_data"][:user]["password"] = params[:user][:password]
@profile = @user.build_profile
render :new_profile
end
def create_profile
@user = User.new(session["devise.regist_data"]["user"])
@profile = Profile.new(profile_params)
unless @profile.valid?
render :new_profile
end
@user.build_profile(@profile.attributes)
@user.save
session["devise.regist_data"]["user"].clear
sign_in(:user, @user)
redirect_to root_path
end
private
def profile_params
params.require(:profile).permit(:avatar, :favorite_beer, :twitter_link, :info)
end
この中の以下の記述が悪さをしていた様子。
@user.build_profile(@profile.attributes)
@user.save
ここでは、@userと@profileをbuildで関連付けさせて@user.saveでまとめて保存をしているのですが、ここでの保存が原因で上手く行ってない様子。
この記事を見つけて
原因
ActiveStorageに実際にファイルが保存されるタイミングはmodelをsaveして処理がコミットされた時なので、保存される前のmodelから画像をattachしてもファイルが未完成の状態になるっぽいです。
どうもActiveStrageはモデルをちゃんとsaveしないと行けなさそうなので以下のように記述を変更したら解決しました。
# それぞれのモデルで保存させた
# @user.build_profile(@profile.attributes)
@user.save
@profile.user_id = @user.id
@profile.save
まとめ
正直buildを使っての保存の仕組みがよくわかってなかったのに使用してしまったのがエラーの原因かもしれないです。
少しでも参考になれば幸いです。