QA@IT

画面/アクション移動時のインスタンス変数

10235 PV

初めまして。

以下は、現在作成しているコードの概要なのですが、画面をCheckからHomeにリダイレクトするとインスタンス変数@received_formがnilになることに気付きました。

コントローラ (checkとformの2つのアクションがある)

def check
  (略)
  @received_form = 値を設定
  if success
     flash[:success] = "成功です"
  else
     flash[:error] = "失敗です"
     redirect_to home_path
  end
end

def home
   p "@RECEIVED_STRINGS: ", @received_string   #デバッグ用
end

Homeビュー (form_tagの中のみ)

<%= text_area_tag(:form_text, @received_string %>

Checkビュー (form_tagの中のみ)

<%= text_area_tag(:form_text, @received_string %>

以下が質問です。

  • インスタンス変数は、redirect_toを行なうと消えてしまう、つまり各アクションは別のインスタンスであるという理解で合っていますでしょうか?
  • アクション同士で値を共有するのであれば、通常はデータベースに保存して受け渡しすると思います。ここでは訳あって値をデータベースに保存せずにアクション同士でこのフォームの値を受け渡ししたいと考えています。その場合はどのような方法で値を受け渡すのがベストでしょうか。何となくですが、クラス変数@@received_textにするのは違うような気がしました。
  • 値を保存するヘルパーメソッドを作成してそれを経由して受け渡すというのを考えたのですが、これはよい方法でしょうか。その場合ヘルパーメソッドの寿命は何に依存しますでしょうか。
  • あるいは、ヘルパーメソッドではなく、そのためのモデルを作成してそこに値を一時保存すべきでしょうか。

よろしくお願いします。

回答

質問内容のなかでいくつかわからない部分がありましたので、わかる部分だけ回答します。

インスタンス変数は、redirect_toを行なうと消えてしまう、つまり各アクションは別のインスタンスであるという理解で合っていますでしょうか?

おおむね合っています。もし複数のリクエストにまたがって Controller のインスタンス変数を共有してしまったら、複数のユーザがアクセスしたときに問題が発生しやすくなりますよね。

アクション同士で値を共有するのであれば、通常はデータベースに保存して受け渡しすると思います。ここでは訳あって値をデータベースに保存せずにアクション同士でこのフォームの値を受け渡ししたいと考えています。その場合はどのような方法で値を受け渡すのがベストでしょうか。何となくですが、クラス変数@@received_textにするのは違うような気がしました。

  1. セッションを利用する
  2. URL のパラメータを使う

が一般的な方法だと思います。ちなみに、例でお使いになっている flash も、セッションを利用したものです。

# 1. セッションを使う
# シリアライズできるデータならなんでも保持できる (容量の制限はある)。
# デフォルトだと中身をユーザが見ることができる。
# ややデバッグしづらい。
def check
  # 値の保存
  session[:received_form] = "foo"
end

def home
  # 値の取得
  @received_form = session[:received_form]
end
# 2. URL のパラメータを使う
# 文字列しか渡せない。
# 容量の制限が厳しい (URL が長くなりすぎると Web サーバが拒否することが多い)。
# ユーザに見える、ユーザが自由に書き換えられる。
def check
  # /home?received_form=foo のような URL を生成してリダイレクト
  redirect_to home_path(received_form: "foo")
end

def home
  # params でアクセスできる
  @received_form = params[:received_form]
end

もっとも、今回の例の場合、rails g scaffold で生成される create, update アクションのように、リダイレクトしないで render action: "home" でもよさそうに見えます。

なお、クラス変数は Rails のプロセスが終了するまで共有されます。複数のユーザがアクセスしたときに問題になりますので、この用途で使うべきではありません。

編集 履歴 (0)
  • 丁寧なご回答ありがとうございました!おかげさまで疑問点を解消できました。
    ちなみにもともとやりたかったのはFlashメッセージが重複して表示される(同じページで再表示すると1つ前のメッセージが残ってしまう)問題の解決だったのですが、不要なメッセージを""にしてERB側で空のメッセージを非表示するという方法で回避しました。

    それにしても、このサイトのQ&Aはレベルが高くてよいですね。
    -
  • 質問にわかりにくいところがあり、失礼しました。 -
ウォッチ

この質問への回答やコメントをメールでお知らせします。