ウィザード形式でデータを保存できない‥

こんにちは
オリアプ作成中に思うような実装にならなかったので
メモの代わりに記事にしました。

# 実装したい機能

ユーザー新規登録を行う際に、
admin_usersテーブルと詳細なプロフィールの
投稿を行うadmin_profilesテーブルを生成しました。

admin_usersテーブル

```rb
t.string :store_name,         null: false
t.string :email,              null: false, default: '', unique: true
t.string :encrypted_password, null: false, default: ''
```

admin_profilesテーブル

```rb
      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モデル

```rb
  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モデル

```rb
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の関係で
admin_user has many admin_profile
admin_profile belongs_to admin_user

このadmin_usersテーブルとadmin_profilesテーブルを使用して
ユーザー登録機能をウィザード形式で実装することを試みました。

# エラー表示は起こらないのにデータが保存されない‥

admin_users/registrations_controller

```rb
 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の

```rb
@admin_user.build_admin_profile(@admin_profile)
    @admin_user.save
```

これを

```rb
    @admin_user.save
    @admin_profile.admin_user_id = @admin_user.id
    @admin_profile.save
```

に変更してやったら無事全て保存することができました！！