So I'm building an e-commerce platform that processes payments via Stripe. Once this has been successfully processed I want to create an Order entry for page admins to see on an Orders page.
Stripe successfully processes payment, Then Order is created by adding an entry that captures:
Product and Price are being pulled successfully, but unfortunately @user.id isn't being pulled into the record. I get the following error : "undefined method `id' for nil:NilClass".
** Payments Controller **
class PaymentsController < ApplicationController
def create
token = params[:stripeToken]
@product = Product.find(params[:product_id])
@user = current_user
# Create the charge on Stripe's servers - this will charge the user's card
begin
charge = Stripe::Charge.create(
:amount => (@product.price*100).to_i, # amount in cents, again
:currency => "usd",
:source => token,
:description => params[:stripeEmail]
)
if charge.paid
Order.create!(
product_id: @product.id,
user_id: @user_id,
total: @product.price)
end
flash[:success] = "Payment processed successfully"
rescue Stripe::CardError => e
#Card was declined
body = e.json_body
err = body[:error]
flash[:error] = "Unfortunately, there was an error processing your payment: #{err[:message]}"
end
redirect_to product_path(@product)
end
end
** orders Controller**
class OrdersController < ApplicationController
protect_from_forgery with: :null_session
def index
end
def show
end
def create
end
def destroy
end
end
** Show page where I am rendering the payments partial (via Stripe)**
<div class="col-md-6 center text-center">
<div class="container">
<div class="header-spacing">
<%= image_tag(@product.image_url, class:" img-responsive center") %>
</div>
<h2>
<%= @product.name %>
</h2>
<h4>
<%= @product.desc %>
<%= @product.style %>
<strong>$<%= '%.2f' % @product.price %></strong>
</h4>
<%= form_tag("/payments/create", remote: true) do %>
<%= render partial: "shared/stripe_checkout_button" %>
<%= hidden_field_tag(:product_id, @product.id) %>
<% end %>
</div>
</div>
** My OrdersController **
class OrdersController < ApplicationController
# before_filter :authenticate_user!
protect_from_forgery with: :null_session
def index
end
def show
end
def create
@order = Order.create(order_params)
respond_with @order
end
def destroy
end
private
def order_params
params.require(:order).permit(:product_id, :user_id, :total)
end
end
Now I've already considered adding:
<%= hidden_field_tag(:user_id, @user.id) %>
But I get the exact same error.
Any help would be greatly appreciated.
UPDATE
It turned out the AJAX request I was making didn't carry the CSRF token. For that reason, Rails was killing my session. I added skip_before_filter :verify_authenticity_token in my paymentsController and all is well now.
But I would still like to know how to fix/why this is happening, if anyone has any info
UPDATE 2
Now that I understand the problem better, I've found an older post dealing with the issue, might be helpful to others.
Essentially form_tag's do not automatically generate CSRF tokens, unless explicitly told to do so, however neither do form_for tag's, as they chopped that in Rails 4.
I simply resolved the issue by adding a hidden input in my form:
<%= form_tag("/payments/create", remote: true) do %>
<%= render partial: "shared/stripe_checkout_button" %>
<%= hidden_field_tag(:product_id, @product.id) %>
<input type="hidden" value="<%= form_authenticity_token() %>"name="authenticity_token"/>
<% end %>
The main reason they chopped automatic generation of CSRF tokens has to do with people fragment-caching because the authenticity token would be wrong on subsequent requests when the form was pulled from the cache.