質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.91%

railsで確認画面から入力画面戻っても変数の内容を維持したい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 4,682

score 41

実現したいこと

ruby on railsで確認画面(confirmアクション)と新規作成画面(newアクション)に戻るボタン付きの新規作成機能を実装しています。
アクションを跨がっても変数を維持したいのですが、
confirmからnewに戻ったとき、変数を維持する方法がわからなくて困っています。

現状の詳細と問題点

Accountのshowページに、取引記録の新規作成画面(account_transactions_conntrollerのnewアクション)へ飛ぶリンクを設置しています。

app/view/account/show.html.erb

<%= link_to "記録作成する", new_account_transaction_path(:account_number => @account1.account_number), class: 'btn btn-danger btn-lg' %>


link_toには、どのアカウントか分かるようにaccount_numberを付与し、account_transactions_controllerのnewアクションに渡して、クラス変数@accountに入れています。

この後、クラス変数@accountに入っているaccount_number(アカウントのレコード)は、
入力画面と確認画面ではアカウント情報表示の為、
createでは新規作成用のフォームオブジェクトにパラメータ(new_account_transaction_form_params)に含まれていない値(account_number)を渡すために
使っています。

class AccountTransactionsController < ApplicationController


  def new
    #Accountのshowページのlink_toで生成されたパラメータを元に、アカウントを取得。
    @@account = Account.find_by(account_number: account_number_params)#問題の部分,確認画面から戻るとAccountのlink_toからのパラメータがないため中身がない状態になってしまう。
    @account = @@account

    #作成用フォームオブジェクトに受け渡す
    @account_transaction = NewAccountTransactionForm.new

  end

  #取引内容を確認する画面
  def confirm
    #newアクションで取得したクラス変数
    @account = @@account
    @account_transaction = NewAccountTransactionForm.new(new_account_transaction_form_params)
    return if @account_transaction.valid?
    render :new

  end

  #確認画面で戻るボタンを押したときnew画面に戻れるようにする
  def back
    @account_transaction = NewAccountTransactionForm.new(new_account_transaction_form_params)
    render :new
  end

  #取引を作成して記録する
  def create
    #新規作成用フォームオブジェクトに渡す
    @account_transaction = NewAccountTransactionForm.new(new_account_transaction_form_params)
    #パラメータに含まれていないものをフォームオブジェクトに渡す、newアクションで取得したクラス変数の内容を渡す
    @account_transaction.account_number = @@account.account_number

    if @account_transaction.post_transaction
      redirect_to root_path
      flash[:notice] = '記録しました'
    else
      render :new
      flash[:notice] = '失敗しました。もう一度試してみてください。'
    end
  end

  private
  #フォームオブジェクトに渡す用(ユーザーが入力したもの)
  def new_account_transaction_form_params
    params.require(:new_account_transaction_form).permit(:amount)
  end

  #accountのshowページのlink_toからのパラメータ(ユーザー未入力、自動)
  def account_number_params
    params.require(:account_number)
  end

end

app/view/account_transactions/new.html.erb(入力画面)

<p>アカウント番号_<%= @account.account_number %></p>
<%= form_for @account_transaction, url: {action: 'confirm'} do |f| %><!-- 確認画面への移動-->

  <div class="field">
    <%= f.label :送金額 %>
    <%= f.number_field :amount,min:1,max:999999 %>
  </div>
  <div class="actions">
    <%= f.submit '取引確認画面へ' %>
  </div>
<% end %>


app/view/account_transactions/confirm.html.erb

<h1>確認画面</h1>
<p>送金口座番号_<%= @account.account_number %></p>

<%= form_for @account_transaction, url: {action: 'create'} do |f| %><ユーザー入力内容表示中、submitボタンが押されるとcreateアクションを実行する用-->
  <div class="field">
      <%= f.label :取引額:, class: "label-inline" %>
    <%= @account_transaction.amount %>
    <%= f.hidden_field :amount %>
  </div>
  <div class="actions">
    <%= f.submit '取引を確定する' %>
  </div>
<% end %>

<%= form_for @account_transaction, url: new_account_transaction_path do |f| %><!-- 入力画面に戻る用 -->
  <%= f.hidden_field :amount %>
  <%= f.submit '入力画面へ戻る'%>
<% end %>

一応上記のコードで、new画面に戻ることはできるのですが、戻ったときに、
Accoutのshowページのlink_toから受け取った値を入れてある@@accountがリセットされてしまい中身がないままになるという問題が発生してしまいます。
確認画面からnew画面に戻ったときは、Accountのshowページからのlink_toパラメータがつくられないことが原因だと思いますが、
もし、この@@accountの内容を維持したい場合はどうすればいいのか、教えて頂ければ幸いです。

追記(アドバイスに従い修正、ミスあり)

ルーティング設定を変更。

Rails.application.routes.draw do


  #アカウント関連
  resources :accounts, :only => [:index,:show]
  resources :accounts do
    resources :transactions, controller: :account_transactions
    member do
      post 'confirm', :transactions, controller: :account_transactions#問題の部分
    end
  end

  #取引記録関連
  resources :account_transactions, :only => [:new, :create, :index, :show]

  resources :account_transactions do
    collection do
      post 'confirm'#記録内容確認画面用
    end
  end

end
コード

最終追記(アドバイスに従い最終的に成功したコード)

ルーティングの設定です。

  resources :users do
    resources :transactions, controller: :account_transactions do
      collection do
        post 'confirm'#確認画面
      end
    end
  end
#このコードにより、user_id(アクションを跨がっても維持したい情報)を含めたURLパターンになる。
#/users/:user_id/transactions/confirm(.:format)
#/users/:user_id/transactions/new(.:format)


あとは、各アクションで、
 @account = BasicIncomeAccount.find_by(user_id: params[:user_id])
と入力すれば、アクションを跨いでも同じ内容を取得できました。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

クラス変数は使わないほうが良いです、このような場合はURLパラメータを常に渡し続けるべきです
ただし、毎回指定するのが手間だし、未指定は許容しないわけなので
URLパラメータが必須であることをRoutingで設計するほうが良いでしょう  

routes.rb

# GET : accounts/:account_id/transactions/new
# POST: accounts/:account_id/transactions
resources :accounts do
  resources :transactions, controller: :account_transactions
end

そうすると最初こそ、 account_id を指定する必要がありますが

show.html.erb

<%= link_to "記録作成する", new_account_transaction_path(account_id: @account1.id), class: 'btn btn-danger btn-lg' %>

transaction下の画面では ***_path を実行する時には渡ってきた account_id がデフォルト値になるため、指定せずパラメータが引き継がれます

■補足
コントローラーでは毎回 Account.find(params[:account_id]) を行います
account_numberはidで取得した後に参照すれば良いので、URLで渡す必要はないという認識で書いています
もし Account.id がなくて、 account_number がプライマリーキーなら、適宜読み替えるなりしてください
 

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/10/18 18:27 編集

    アドバイス通り、ルーティング設定を変更してみました。(変更内容は、質問文に追記しました)
    resources :accountsでnewやcreateといったCRUDのURLパラメータに、account_idを含めることはできたのですが、独自追加したconfirmでは失敗してしまいます。

    URLパターンも、
    /users/:user_id/transactionsではなく
    /users/:id/confirmという風になっています。

    memberで追加した独自のルーティング(confirm)に、
    account_idを含めるよう設定するのはどうすればいいのでしょうか?

    キャンセル

  • 2018/10/19 08:31 編集

    account_transactionsの関数を増やすのでブロックの位置が違います
    また、transaction_id が不要なら menber ではなく collection になります

    resources :accounts do
     resources :transactions, controller: :account_transactions do
      collection do
       post 'confirm'
      end
     end
    end

    キャンセル

  • 2018/10/19 23:17

    Ighrsさん、丁寧な説明ありがとうございます。おかげで解決することができました!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.91%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る