本記事の内容
アクション間で同じインスタンスを使いたいことがありました。
今回は、アクション間で同じインスタンス変数を使い回す方法を解説しています。
要件
1.ユーザー登録画面では、ユーザー名とメールアドレスのみを入力
2.入力されたメールアドレス宛に確認コードを送信、ユーザーが確認コードを入力する
このように、「ユーザー名・メールアドレス・確認コード」の3つを同じFormオブジェクトで管理しているが、別々のviewでそれぞれ入力したい場合があります。
この時、ユーザー登録画面から確認コード入力画面にリダイレクトするため、
ユーザー登録画面で作成したインスタンス変数は本来ならば、消えてしまいます。
今回は、ユーザー登録画面で入力された内容を保持して確認コード入力画面に遷移できるようにしたいと思います。
実装方法
結論としては、セッションを用います。
リダイレクト前にインスタンスをセッションに詰め、リダイレクト先でセッションから再度インスタンスを作成します。
def create
〜〜(バリデーションチェックなど)〜〜
# インスタンス変数をセッションに詰める
session[:user_form] = @user_form
redirect_to verify_email_path
end
def verify_email
# セッションから再度インスタンスを作成
@user_form = UserForm.new(session[:user_form])
end
しかし、これだけだと下記画像のような、errosという属性がないというエラーが発生します。
これは、バリデーションチェックした後では、自動でインスタンス変数にerrors
とvalidation_context
という属性が追加され、これに対応するFormオブジェクトのセッターがなく値をセットできないことが原因です。
↓binding.pry
で確認した@user_form
{"errors"=>{}, "name"=>"テスト", "email"=>"test@sample.com", "validation_context"=>nil}
そのため、Formオブジェクトのコンストラクタを下記のように編集します。
ActiveModel::ModelをincludeしたFormオブジェクトは、デフォルトでActiveModel::Modelのinitializeメソッドを使用するため、今回はFormオブジェクト内で特定の属性のみ初期化するinitializeメソッドを定義する必要があるためです。
class UserForm
include ActiveModel::Model
attr_accessor :name, :email, :verify_code
def initialize(attribute = {})
→ @name = attribute['name']
→ @email = attribute['email']
end
end
以上です!!
今回のサンプルコード
こちらです⤵︎⤵︎
ご拝読ありがとうございました!!m(_ _)m