2015-05-25 1 views
0

Как и другие, работающие с платежами Stripe, я получаю сообщение об ошибке «Не может взимать плату с клиента, у которого нет активной карты». Форма не добавляла токен, потому что у javascript не было соответствующего идентификатора в форме, но теперь я получаю ошибку рельсов, и плата не взимается, клиент создается, ошибка указывает на наличие недопустимой строки элемент, когда код для создания клиента и плата за карту не выполняется, заказ создается без ошибок.рельсы 4 полоса платежа, вызывающая недействительную позицию позиции

Заказать Просмотр

<script type="text/javascript" src="https://js.stripe.com/v2/"> 

$(function(){ 

    Stripe.setPublishableKey('<%= Rails.configuration.stripe[:PUBLISHABLE_KEY] %>'); 

}); 

</script> 

<div class = "Power Me" > 

    <fieldset> 

    <legend> Please enter your details </legend> 

    <%= render 'form', object: @object %> 

    </fieldset> 

</div> 

Вынесено Форма заказа

<%= form_for(@order, :html => {:id => 'payment-form'}) 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="field"> 

    <%= "Order Total: #{order_total.to_s}" %> 
    <%= "Order Currency: #{order_currency.to_s}" %> 
    </div> 

    <div class="field"> 
    <%= f.label :name %><br> 
    <%= f.text_field :name %> 
    </div> 
    <div class="field"> 
    <%= f.label :Address_line_1 %><br> 
    <%= f.text_area :address_line_1 %> 
    </div> 
    <div class="field"> 
    <%= f.label :Address_Line_2 %><br> 
    <%= f.text_area :address_line_2 %> 
    </div> 
    <div class="field"> 
    <%= f.label :City %><br> 
    <%= f.text_area :address_city %> 
    </div> 
    <div class="field"> 
    <%= f.label :Region %><br> 
    <%= f.text_area :address_state %> 
    </div> 
    <div class="field"> 
    <%= f.label :Postcode %><br> 
    <%= f.text_area :address_zip %> 
    </div> 
    <div class="field"> 
    <%= f.label :Country %><br> 
    <%= f.select :address_country, Order::CC_COUNTRIES, prompt: 'Select the country' %> 
    </div> 
    <div class="field"> 
    <%= f.label :email %><br> 
    <%= f.text_field :email, :placeholder => "[email protected]" %> 
    </div> 
    <div class="field"> 
    <%= f.label :Payment_Type %><br> 
    <%= f.select :pay_type, Order::PAYMENT_TYPES, prompt: 'Select a payment method' %> 
    </div> 
    <div class="form-row"> 
     <label>Card Number</label> 
     <input type="text" size="20" autocomplete="off" data-stripe="number" id="number" class="credit-number", placeholder = "**** **** **** ****" pattern="[\d ]*" /> 
    </div> 

    <div class="form-row"> 
     <label>Security Code/CVC</label> 
     <input type="text" size="4" autocomplete="off" data-stripe="cvc" id="cvc" class="credit-scurity" placeholder="***" pattern="\d*" /> 
    </div> 

    <div class="form-row"> 
     <label>Expiration (MM/YYYY)</label> 
     <input type="text" size="2" data-stripe="exp-month" id="exp-month" class="card-expiry-month" placeholder="MM" pattern="\d*" /> 
     <span>/</span> 
     <input type="text" size="4" data-stripe="exp-year" id="exp-year" class="card-expiry-year" placeholder="YYYY" pattern="\d*" /> 
    </div> 

    <div class="actions"> 
    <%= f.submit 'Pay', :class =>"stripe-button" %> 
    </div> 
<% end %> 

заказы модели

class Order < ActiveRecord::Base 

# attr_accessor :stripeToken 

    PAYMENT_TYPES = ["credit card"] 

    CC_COUNTRIES = ["United Kingdom", "France", "Italy"] 

    validates :name, :address_line_1, :address_zip, :email, presence: true 

# validates :pay_type, inclusion: PAYMENT_TYPES 

    has_many :line_items, dependent: :destroy 

    def add_line_items_from_cart(cart) 

    cart.line_items.each do |item| 

     item.cart_id = nil 

     line_items << item 

    end 

    end 
end 

Приказы Контроллер

class OrdersController < ApplicationController 

    include CurrentCart 

    before_action :set_cart, only: [:new, :create] 

    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 

    if @cart.line_items.empty? 

     redirect_to store_url, notice: "Your cart is empty" 

     return 

    end 

    @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 

     Cart.destroy(session[:cart_id]) 

     session[:cart_id] = nil 

     format.html { redirect_to @order, notice: 'Order was successfully created.' } 
     format.json { render action: 'show', status: :created, location: @order } 
     else 
     format.html { render action: 'new' } 
     format.json { render json: @order.errors, status: :unprocessable_entity } 
     end 
    end 

    Stripe.api_key = "sk_test_BsdqHq0SQuPqHIsm46lcpX4v" 

    @amount = order_total.to_i * 100 

    token = params[:stripeToken] 
=begin 
    begin 

     customer = Stripe::Customer.create(

     :email => order_params[:email] 

    ) 

     charge = Stripe::Charge.create(

     :customer => customer.id, 
     :amount => @amount, # amount in cents, again 
     :currency => order_currency, 
     :card => token, 
     :description => order_params[:email] 
    ) 

     redirect_to root_path 

    rescue Stripe::CardError => e 

     @error = e 

    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 { head :no_content } 
     else 
     format.html { render action: '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 } 
     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(:name, :email, :pay_type, :address_line_1, :address_line_2, :address_city, :address_state, :address_zip, :address_country) 
    end 
end 

Мой Application Helper

module ApplicationHelper 

     def order_total 

     total = LineItem.joins(:product).select("sum(line_items.quantity * products.price) as total").where("cart_id = ?", session[:cart_id]).first.total 

     end 

     def order_currency 

     currency = LineItem.joins(:product).joins(:currency).select("currencies.name as iso_name").where("cart_id = ?", session[:cart_id]).first.iso_name 

     end 


     # Returns the full title on a per-page basis. 
     def full_title(page_title) 
     base_title = "Ruby on Rails Tutorial Sample App" 
     if page_title.empty? 
      base_title 
     else 
      "#{base_title} | #{page_title}" 
     end 
     end 

     def bootstrap_class_for flash_type 

     { success: "alert-success", error: "alert-danger", alert: "alert-warning", notice: "alert-info" }[flash_type] || flash_type.to_s 

     end 

     def flash_messages(opts = {}) 

     flash.each do |msg_type, message| 

      concat(content_tag(:div, message, class: "alert #{bootstrap_class_for(msg_type)} fade in") do 

      concat message 
     end) 

     end 

      nil 

     end 

     # before filters 

     def signed_in_user 

     unless signed_in? 

      store_location 

      redirect_to signin_url, notice: "Please sign in." 

     end 

     end 

     def correct_user 

     @user = User.find(params[:id]) 

     redirect_to(root_url) unless current_user?(@user) 

     end 

     def admin_user 

     redirect_to(root_url) unless current_user.admin? 

     end 

end 

Orders.js

$('#payment-form').submit(function(event) { 

    var form = $(this); 

    form.find('button').prop('disabled', true); 

    Stripe.createToken(form, stripeResponseHandler); 

    return false; 

}); 
+0

Я бы удостоверился, что stripeToken на самом деле установлен и не равен нулю. Ваш текущий код должен вызывать ошибку «Клиент cus_XXXXXXX не имеет карты с идентификатором tok_YYYYYYYYYYY» –

+0

спасибо, что было частью проблемы – Conor

ответ

0

Рабочий бланк заказа ниже, вы не можете передать поля чередуют и использовать их в рельсах форме, чтобы сохранить в БД, его либо или (Предыдущий пример попытался сохранить адресные поля в db и передать их в полосу как часть проверки транзакции.

<%= form_for(@order, :html => {:id => 'payment-form'}) 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="field"> 

    <%= "Order Total: #{order_total.to_s}" %> 
    <%= "Order Currency: #{order_currency.to_s}" %> 

    </div> 

    <div class="form-row"> 
     <label>Full Name</label> 
     <input type="text" size="20" autocomplete="off" data-stripe="name" /> 
    </div> 

    <div class="field"> 
    <%= f.label :email %><br> 
    <%= f.text_field :email, :placeholder => "[email protected]" %> 
    </div> 
    <div class="field"> 
    <%= f.label :Payment_Type %><br> 
    <%= f.select :pay_type, Order::PAYMENT_TYPES, prompt: 'Select a payment method', :selected => "credit card" %> 
    </div> 

    <div class="form-row"> 
     <label>Address Line 1</label> 
     <input type="text" size="20" autocomplete="off" data-stripe="address_line1" /> 
    </div> 

    <div class="form-row"> 
     <label>Address Line 2</label> 
     <input type="text" size="20" autocomplete="off" /> 
    </div> 

    <div class="form-row"> 
     <label>Address City</label> 
     <input type="text" size="20" autocomplete="off" /> 
    </div> 
    <div class="form-row"> 
     <label>Address State</label> 
     <input type="text" size="20" autocomplete="off" /> 
    </div> 


    <div class="form-row"> 
     <label>Zip/Postcode</label> 
     <input type="text" size="20" autocomplete="off" data-stripe="address_zip" /> 
    </div> 



    <div class="form-row"> 
     <label>Country</label> 
     <input type="text" size="20" autocomplete="off" data-stripe="address_country" /> 
    </div> 
    <div class="form-row"> 
     <label>Card Number</label> 
     <input type="text" size="20" autocomplete="off" data-stripe="number" placeholder = "**** **** **** ****" pattern="[\d ]*" /> 
    </div> 

    <div class="form-row"> 
     <label>Security Code/CVC</label> 
     <input type="text" size="4" autocomplete="off" data-stripe="cvc" placeholder="***" pattern="\d*" /> 
    </div> 

    <div class="form-row"> 
     <label>Expiration (MM/YYYY)</label> 
     <input type="text" size="2" data-stripe="exp-month" placeholder="MM" pattern="\d*" /> 
     <span>/</span> 
     <input type="text" size="4" data-stripe="exp-year" placeholder="YYYY" pattern="\d*" /> 
    </div> 

    <div class="actions"> 
    <%= f.submit 'Pay', :class => "button" %> 
    </div> 
<% end %> 

форма требуется идентификатор, на который ссылается Inthe JavaScript ниже

var stripeResponseHandler = function(status, response) { 
    var $form = $('#payment-form'); 

    if (response.error) { 
    // Show the errors on the form 
    $form.find('.payment-errors').text(response.error.message); 
    $form.find('button').prop('disabled', false); 
    } else { 
    // token contains id, last4, and card type 
    var token = response.id; 
    // Insert the token into the form so it gets submitted to the server 
    $form.append($('<input type="hidden" name="stripeToken" />').val(token)); 
    // and re-submit 
    $form.get(0).submit(); 
    } 
}; 


jQuery(function($) { 

    $('#payment-form').submit(function(e) { 
    var $form = $(this); 

    // Disable the submit button to prevent repeated clicks 
    $form.find('button').prop('disabled', true); 

    Stripe.card.createToken($form, stripeResponseHandler); 

    // Prevent the form from submitting with the default action 
    return false; 
    }); 
}); 

заказа модели, поля удалены

class Order < ActiveRecord::Base 

    PAYMENT_TYPES = ["credit card"] 

    CC_COUNTRIES = ["United Kingdom", "France", "Italy"] 

    validates :email, presence: true 

    validates :pay_type, inclusion: PAYMENT_TYPES 

    has_many :line_items, dependent: :destroy 

    def add_line_items_from_cart(cart) 

    cart.line_items.each do |item| 

     item.cart_id = nil 

     line_items << item 

    end 

    end 
end 

заголовок приложения

<!DOCTYPE html> 
<html> 
    <head> 
    <title><%= full_title(yield(:title)) %></title> 
    <%= stylesheet_link_tag "application", media: "all", 
              "data-turbolinks-track" => true %> 
    <%= javascript_include_tag "application", "data-turbolinks-track" => true %> 
    <script type="text/javascript" src="https://js.stripe.com/v2/"></script> 
    <script type="text/javascript"> 

     $(function(){ 

     Stripe.setPublishableKey('<%= Rails.configuration.stripe[:publishable_key] %>'); 

     }); 

    </script> 
    <%= csrf_meta_tags %> 
    <%= render 'layouts/shim' %> 
    </head> 
    <body> 

Заказать Контроллер

class OrdersController < ApplicationController 

    include CurrentCart 

    before_action :set_cart, only: [:new, :create] 

    before_action :set_order, only: [:show,:edit, :update, :destroy] 

# before_action :admin_user, only: [:destroy, :show] 


    # 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 

    if @cart.line_items.empty? 

     redirect_to store_url, notice: "Your cart is empty" 

     return 

    end 

    @order = Order.new 

    end 

    # GET /orders/1/edit 
    def edit 
    end 

    # POST /orders 
    # POST /orders.json 
    def create 

    begin 

     @order = Order.new(order_params) 

     @order.add_line_items_from_cart(@cart) 

     Stripe.api_key = "sk_test_xxxxxxxxxxxxxxx" 

     @amount = order_total.to_i * 100 

     token = params[:stripeToken] 

     # Create a Customer 
     customer = Stripe::Customer.create(

     :description => order_params[:email], 
     :card => token, 

    ) 


     charge = Stripe::Charge.create(

     :customer => customer.id, 
     :amount => @amount, # amount in cents, again 
     :currency => order_currency, 
     # :card => token, 
     :description => order_params[:email] 
    ) 

     respond_to do |format| 

     if @order.save 

      puts "saving now" 

      Cart.destroy(session[:cart_id]) 

      session[:cart_id] = nil 

      format.html { redirect_to @order, notice: 'Order was successfully created.' } 
      format.json { render action: 'show', status: :created, location: @order } 
     else 
      format.html { render action: 'new' } 
      format.json { render json: @order.errors, status: :unprocessable_entity } 
     end 
     end 

     rescue Stripe::CardError => e 

     flash[:error] = e.message 
     redirect_to root_path 
    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 { head :no_content } 
     else 
     format.html { render action: '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 } 
     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(:email, :pay_type) 

    end 
end 
Смежные вопросы