Reputation: 2900
I'm trying to create an order confirmation page for my Rails 6 app. The idea is that user will see a preview of the item they are creating before submitting and the object being saved in the database. Below desired flow:
I followed two main threads that describe this type of action, but they are quite old - 11 and 12 years old. Nevertheless based on that I've created below code:
# controllers/cash_transactions/withdrawals_controller.tb
module CashTransactions
class WithdrawalsController < CashTransactions::BaseController
(...)
def confirm
@cash_transaction = CashTransaction.new(cash_transaction_params)
render 'cash_transactions/_confirm'
end
end
end
# routes.rb
namespace :cash_transactions do
resources :withdrawals, only: %i[new create] do
collection do
post :confirm
end
end
end
With corresponding views:
# app/views/cash_transactions/new.html.erb
<%= render 'cash_transactions/form', cash_transaction: @cash_transaction %>
# views/cash_transactions/_form
# the form is rendered for cash_transaction create action
<%= simple_form_for cash_transaction, url: { action: :confirm } do |f| %>
<%= f.input :amount %>
<%= f.button :submit, 'Submit' %>
<% end %>
# confirmation page under views/cash_transactions/_confirm.html.erb
<div>
Total of withdrawal: <%= @cash_transaction.amount.to_i %>
</div>
<%= link_to 'Confim', cash_transactions_withdrawals_path(@cash_transaction), method: :post %>
<%= link_to 'Cancel', cash_transactions_path %>
And everything works until the user clicks confirm
button in views/cash_transactions/_confirm.html.erb
- instead of creating a record an error appears:
param is missing or the value is empty: cash_transaction Did you mean? authenticity_token action controller _method
where did I go wrong? or there is a completely different way to do so?
Upvotes: 0
Views: 658
Reputation: 1601
tl/dr: You need to add parameters to your create request.
Why this is happening
The /confirm
view is being rendered with an (unsaved) @cash_transaction
object, however that object is not being used and so the information is being lost when the page is rendered.
The line:
<%= link_to 'Confim', cash_transactions_withdrawals_path(@cash_transaction), method: :post %>
Will submit a POST
request with no parameters to the /cash_transactions/withdrawals#create
(because you've given it no parameters to post). It doesn't know to include the params from the previous request.
There are a few options to fix this... you can add params as URL parameters in link_to like this, however I wouldn't recommend posting with params in the URL.
You can use button_to
instead, and pass in the cash_transaction
arguments from the previous request in the params:
option (or pull them out of the unsaved @cash_transaction object).
Approach #1 - reuse create params
# Get them from the params sent in the previous request. In the controller...
def create
@cash_transaction = CashTransaction.create!(cash_transaction_params)
# etc...
end
#...
protected
def cash_transaction_params
params[:cash_transaction].permit(:amount, :whatever)
end
helper_method :cash_transaction_params
# In the view
<%= button_to 'Confirm', {action: 'create', params: cash_transaction_params}
Approach #2 - Access attributes from the model you built
<%= button_to 'Confirm', {action: 'create', params: @cash_transaction.attributes.slice('amount', 'other_attribute') }
Or you could do something like render the form again but hidden and have the "confirm" button submit the hidden form (with { action: :create }
instead of { action: :confirm}
). This last solution is probably the easiest to understand.
Upvotes: 1