Robbo
Robbo

Reputation: 1312

Stripe "invalid_request_error" - Card number not being passed from form to model method

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

Answers (1)

Kirti Thorat
Kirti Thorat

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

Related Questions