Possible Missing Value with Parameters in Rails Application
I'm new to Rails and I have no idea what's going on here. The app I'm building is an online store. The current functionality works, but the change I'm trying to implement doesn't work. As a starting point, I'll show you the working version I currently have. Here is my /show.html.erb directory:
<p id="notice"><%= notice %></p>
<h2>My Cart</h2>
<table class="table table-responsive table-striped">
<thead>
<tr>
<th>Item</th>
<th>Quantity</th>
<th>Total Price in Galleons</th>
<th>Total Price in Muggle Currency</th>
</tr>
<tbody>
<%= render(@cart.line_items) %>
<tr>
<td>Total</td>
<td><%= number_to_currency(@cart.total_price * 7.35) %></td>
<td></td>
<td></td>
</tr>
</tbody>
</thead>
</table>
<br>
<div class="row">
<div class="col-md-3">
<div class="row">
<div class="col-md-4">
<%= link_to 'Back', products_path, :class => 'btn btn-primary whiteText' %>
</div>
<div class="col-md-4">
<%= link_to "Checkout", new_charge_path, :class => 'btn btn-success whiteText' %>
</div>
<div class="col-md-4">
<%= link_to 'Empty Cart', @cart, method: :delete, data: {confirm: 'Are you sure you want to empty your cart?'}, :class => 'btn btn-danger whiteText' %>
</div>
</div>
</div>
<div class="col-md-9"></div>
</div>
However, I want to modify the workflow a bit so that it uses my Order thumbnail to redirect the user to the address confirmation page (orders / new.html.erb) after clicking Checkout on the Cart display page. Once the address is validated, it should then redirect the customer to the payment page, and this is what overrides the new_load_path in my current Checkout link.
So, first, I replace the Checkout link and rotate it out of this:
<%= link_to "Checkout", new_charge_path, :class => 'btn btn-success whiteText' %>
:
<%= link_to "Checkout", new_order_path, method: :get, :class => 'btn btn-success whiteText' %>
This redirect functions as expected and returns me to order / new.html.erb which contains the following:
<h1>Order Information</h1>
<br>
<%= render 'form', order: @order %>
<%= link_to 'Back', products_path %>
The form it provides contains the following code:
<%= form_for(order) do |f| %>
<% if order.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(order.errors.count, "error") %> prohibited this order from being saved:</h2>
<ul>
<% order.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="row">
<div class="col-md-6">
<div class="field">
<%= f.label :first_name %>
<%= f.text_field :first_name, size: 20, :value => current_user.first_name, :class => "form-control" %>
</div>
<div class="field">
<%= f.label :last_name %>
<%= f.text_field :last_name, size: 20, :value => current_user.last_name, :class => "form-control" %>
</div>
<div class="field">
<%= f.label :address %>
<%= f.text_area :address, size: 40, :value => current_user.address, :class => "form-control" %>
</div>
<div class="field">
<%= f.label :city %>
<%= f.text_area :city, size: 20, :value => current_user.city, :class => "form-control" %>
</div>
<div class="field">
<%= f.label :state %>
<%= f.text_area :state, size: 2, :value => current_user.state, :class => "form-control" %>
</div>
<div class="field">
<%= f.label :email %>
<%= f.text_field :email, size: 40, :value => current_user.email, :class => "form-control" %>
</div>
<div class="field">
<%= f.label :pay_type %>
<%= f.select :pay_type, Order.pay_types.keys, prompt: 'Select a payment method', :class => "form-control" %>
</div>
</div>
<div class="col-md-6">
<%= form_tag(payments_path, class: "form-inline") do %>
<%= hidden_field_tag(:purchase_amount_cents, @cart.total_price) %>
<div class="form_group">
<%= label_tag(:credit_card_number, "Credit Card Number", class: "sr-only") %>
<%= text_field_tag(:credit_card_number, "", class: "form-control", placeholder: "Credit Card #") %>
</div>
<br>
<div class="form_group">
<%= label_tag(:expiration_month, "Month", class: "sr-only") %>
<%= text_field_tag(:expiration_month, "", class: "form-control", placeholder: "Month") %>
<br>
<%= label_tag(:expiration_year, "Year", class: "sr-only") %>
<%= text_field_tag(:expiration_year, "", class: "form-control", placeholder: "Year") %>
<br>
<%= label_tag(:cvc, "Year", class: "sr-only") %>
<%= text_field_tag(:cvc, "", class: "form-control", placeholder: "CVC #") %>
</div>
<br>
<div class="form_group">
<%= submit_tag("Purchase Cart", class: "btn btn-default", id: "purchase") %>
</div>
<% end %>
</div>
</div>
<hr>
<div class="actions">
<%= f.submit 'Proceed to Payment' %>
</div>
<% end %>
The payment options are Credit Card (Stripe) or Paypal. I will eventually add the Paypal feature, but the Stripe API is all I have.
Here is my order controller:
class OrdersController < ApplicationController
include CurrentCart
before_action :set_cart, only: [:new, :create]
before_action :ensure_cart_isnt_empty, only: :new
before_action :set_order, only: [:show, :edit, :update, :destroy]
# GET /orders
# GET /orders.json
def index
@orders = Order.all
end
# GET /orders/1
# GET /orders/1.json
def show
end
# GET /orders/new
def new
@order = Order.new
end
# GET /orders/1/edit
def edit
end
# POST /orders
# POST /orders.json
def create
@order = Order.new(order_params)
@order.add_line_items_from_cart(@cart)
respond_to do |format|
if @order.save
format.html { redirect_to new_charge_path}
else
format.html { render :new }
format.json { render json: @order.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /orders/1
# PATCH/PUT /orders/1.json
def update
respond_to do |format|
if @order.update(order_params)
format.html { redirect_to @order, notice: 'Order was successfully updated.' }
format.json { render :show, status: :ok, location: @order }
else
format.html { render :edit }
format.json { render json: @order.errors, status: :unprocessable_entity }
end
end
end
# DELETE /orders/1
# DELETE /orders/1.json
def destroy
@order.destroy
respond_to do |format|
format.html { redirect_to orders_url, notice: 'Order was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_order
@order = Order.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def order_params
params.require(:order).permit(:first_name, :last_name, :address, :city, :state, :email, :pay_type)
end
def ensure_cart_isnt_empty
if @cart.line_items.empty?
redirect_to products_path, notice: 'Your cart is empty!'
end
end
end
Here is my charge controller:
class ChargesController < ApplicationController
include CurrentCart
before_action :set_cart, only: [:new, :create]
def new
end
def create #METHOD IS CALLED AFTER PAYMENT IS MADE
# Amount in cents
@amount = @cart.total_price
customer = Stripe::Customer.create(
:email => params[:stripeEmail],
:source => params[:stripeToken]
)
charge = Stripe::Charge.create(
:customer => customer.id,
:amount => @amount,
:description => 'Customer',
:currency => 'usd'
)
Cart.destroy(session[:cart_id])
rescue Stripe::CardError => e
flash[:error] = e.message
redirect_to new_charge_path
end
end
Here's the problem. While the redirects work as expected, @amount in the Charge controller is set to $ 0.00 if the order controller is used. If, however, the Cart link is directly linked to the Charge controller, then the correct dollar amount is used. So my guess is that somehow the cart object is lost or reset.
Here is my set_cart method:
def set_cart
@cart = Cart.find(params[:id])
end
And here is my CurrentCart module:
module CurrentCart
private
def set_cart
@cart = Cart.find(session[:cart_id])
rescue ActiveRecord::RecordNotFound
@cart = Cart.create
session[:cart_id] = @cart.id
end
end
source to share
My idea is that you need to pass @ cart.total_price value from cart form to order controller here, some steps to follow
inside your link (you pass the value as parameters)
<%= link_to "Checkout", new_order_path(total_price: @cart.total_price), method: :get, :class => 'btn btn-success whiteText' %>
inside order_controller (you get the parameters and put in the instance variabel)
# GET /orders/new
def new
@order = Order.new
@temp_total_price = params[:total_price]
end
inside the insert order_form between your form_for tag, we have to put this in the form as a hidden value, so it can go to create the method for payment
<%= hidden_field_tag 'total_price', @temp_total_price %>
inside your class ChargesController create method you can get total_price
@total_price = params[:total_price]
I know this a bit, but maybe it can help
source to share