こんにちは
オリアプ作成中に思うような実装にならなかったので
メモの代わりに記事にしました。
実装したい機能
ユーザー新規登録を行う際に、
admin_usersテーブルと詳細なプロフィールの
投稿を行うadmin_profilesテーブルを生成しました。
admin_usersテーブル
t.string :store_name, null: false
t.string :email, null: false, default: '', unique: true
t.string :encrypted_password, null: false, default: ''
admin_profilesテーブル
t.string :postal_code, null: false
t.integer :prefecture_id, null: false
t.string :municipality, null: false
t.string :address, null: false
t.string :building_name
t.string :phone_number, null: false
t.text :profile, null: false
t.references :admin_user, null: false
AdminUserモデル
PASSWORD_REGGEX = /\A(?=.*?[a-z])(?=.*?\d)[a-z\d]+\z/i.freeze
validates_format_of :password, with: PASSWORD_REGGEX
validates :store_name, presence: true
has_many :events
has_one :admin_profile
AdminProfileモデル
belongs_to :admin_user, optional: true
has_one_attached :admin_image
extend ActiveHash::Associations::ActiveRecordExtensions
belongs_to :prefecture
with_options presence: true do
validates :postal_code, format: { with: /\A[0-9]{3}-[0-9]{4}\z/ }
validates :prefecture_id, numericality: { other_than: 1, message: "can't be blank" }
validates :municipality
validates :address
validates :phone_number, format: { with: /\A\d{10,11}\z/ }
validates :profile
validates :admin_image
end
AdminProfileモデルで has_one_attached :admin_image
と
記述しているのは、ActiveStrageを用いてプロフィール画像を
保存したいからです。
admin_userとadmin_profileは1対1の関係で
admin_user has many admin_profile
admin_profile belongs_to admin_user
このadmin_usersテーブルとadmin_profilesテーブルを使用して
ユーザー登録機能をウィザード形式で実装することを試みました。
エラー表示は起こらないのにデータが保存されない‥
admin_users/registrations_controller
def new
@admin_user = AdminUser.new
end
def create
@admin_user = AdminUser.new(sign_up_params)
render :new and return unless @admin_user.valid?
session['devise.regist_data'] = { admin_user: @admin_user.attributes }
session['devise.regist_data'][:admin_user]['password'] = params[:admin_user][:password]
@admin_profile = @admin_user.build_admin_profile
render :new_admin_profile
end
def create_admin_profile
@admin_user = AdminUser.new(session['devise.regist_data']['admin_user'])
@admin_profile = AdminProfile.new(admin_profile_params)
render :new_admin_profile and return unless @admin_profile.valid?
@admin_user.build_admin_profile(@admin_profile)
@admin_user.save
session['devise.regist_data']['admin_user'].clear
sign_in(:admin_user, @admin_user)
end
private
def admin_profile_params
params.require(:admin_profile).permit(:admin_image, :postal_code, :prefecture_id, :municipality, :address,
:building_name, :phone_number, :profile)
end
まじで辛かったです。
2週間ほど悩み倒しました。
エラーにはならないしbinding.pryしてみても
paramsにデータは入ってたので
データを保存する段階で何か不備が起きていたのだろうとは思ってましたが、
それがなかなか見つからず‥。
ActiveStroageが邪魔してる
詳細な原因は不明ですが、どうやらActiveStrageがデータの保存の
邪魔をしてたみたいです。
ActiveStrageのファイルが保存されるタイミングって、saveトランザクションが
コミットされた後だそうです。
コミットされた後に保存しようとするから外部キーのadmin_userを
nilの状態で登録しようとしてしまい、ActiveStrageの保存と
admin_user_idの外部キーのvalidationの関係で
保存されなかった説が濃厚です。
なので、
admin_users/registrations_controllerの
@admin_user.build_admin_profile(@admin_profile)
@admin_user.save
これを
@admin_user.save
@admin_profile.admin_user_id = @admin_user.id
@admin_profile.save
に変更してやったら無事全て保存することができました!!