Reputation: 1312
I'm integrating active merchant with Stripe into my rails app and when i check the Stripe log i see the following:
type: "invalid_request_error"
message: "You must supply either a card or a customer id"
The card number is not being passed from the form in my view to the method in my model.
I must need to make an amendment in my controller to get this working but i'm not sure what.
MODEL
class Order < ActiveRecord::Base
has_many :order_products
has_many :products, through: :order_products
attr_accessor :card_number, :security_code, :card_expires_on
def credit_card
@credit_card ||= ActiveMerchant::Billing::CreditCard.new(
:number => card_number,
:first_name => first_name,
:last_name => last_name,
:verification_value => security_code,
:month => card_expires_on{month},
:year => card_expires_on{year}
)
end
def purchase(basket)
response = GATEWAY.purchase(Product.total_basket_price(basket)*100, credit_card)
end
end
CONTROLLER
class OrdersController < ApplicationController
def create
@order = Order.new
basket.each do |item_id|
@order.order_products.build(product: Product.find(item_id))
end
if @order.save!
if @order.purchase(basket)
render "show"
else
render "new"
end
else
render "new"
end
end
end
VIEW
<%= simple_form_for @order do |f| %>
<%= f.input :card_number %>
<%= f.input :security_code, label: "Security code (CVC)" %>
<%= f.input :card_expires_on, as: :date, discard_day: true, add_month_numbers: true, start_year: Date.today.year, end_year: Date.today.year + 10, order: [:month, :year], label: "Card expiration date" %>
<%= f.button :submit, "Confirm and pay" %>
<% end %>
Can anyone suggest a solution?
Many Thanks
Upvotes: 0
Views: 9647
Reputation: 53038
You are not creating the order
object with values passed from the form which is why you receive the error.
Notice: @order = Order.new
in create
action. This would simply create an instance of Order
model with no attributes set.
With Rails 4, you would need to whitelist the attributes (even the virtual attributes) which you would like to be saved.
So, update the @order
instantiation in create
action as below:
@order = Order.new(order_params)
And in the order_params
method in your controller, make sure that you permit the attributes.
UPDATE:
Change your order_params
as below:
def order_params
if params[:order]["card_expires_on(1i)"] && params[:order]["card_expires_on(2i)"] && params[:order]["card_expires_on(3i)"]
## Set "card_expires_on" to a "Date" object created using the three values
## passed from the form "card_expires_on(1i)" and "card_expires_on(2i)", "card_expires_on(3i)"
params[:order][:card_expires_on] = Date.new(params[:order].delete("card_expires_on(1i)").to_i, params[:order].delete("card_expires_on(2i)").to_i , params[:order].delete("card_expires_on(3i)").to_i)
end
params.require(:order).permit(:card_number, :security_code, :card_expires_on )
end
Update credit_card
method in Order
model as shown below:
def credit_card
@credit_card ||= ActiveMerchant::Billing::CreditCard.new(
:number => card_number,
:first_name => first_name,
:last_name => last_name,
:verification_value => security_code,
:month => card_expires_on.month, ## Get "month" from date object
:year => card_expires_on.year ## Get "year" from date object
)
end
Notice:
card_expires_on.month
and NOT card_expires_on{month}
AND
card_expires_on.year
and NOT card_expires_on{year}
As you can see (highlighted) in the params generated upon form submission:
{"utf8"=>"✓", "authenticity_token"=>"ZWlCaOUPbignlnoULIMpfMCcD9NXQ2Czb0hcQyq9ad4=", "order"=>{"first_name"=>"", "last_name"=>"", "email"=>"", "address_1"=>"", "address_2"=>"", "city"=>"", "postal_code"=>"", "country_code"=>"United Kingdom", "card_number"=>"4242424242424242", "security_code"=>"123", "card_expires_on(3i)"=>"1", "card_expires_on(2i)"=>"5", "card_expires_on(1i)"=>"2016"}, "commit"=>"Confirm and pay"}
for the date field card_expires_on
, you receive three different key's named
card_expires_on(1i)
=> which points to "year"
card_expires_on(2i)
=> which points to "month"
card_expires_on(3i)
=> which points to "date" by default set as 1 with a hidden field as you have not allowed it to input it
Upvotes: 2