2017-02-06 17 views
0

ここではStripeのAPIを扱うRails初心者向けのレッスンです。私は、レールアプリの中にピースと呼ばれるモデルを持っています。各ピースにはstatusという整数があります。作品のステータスが1の場合にのみ、作品を購入できるようにします。現在のコードでは、ステータスの部分が1でない限り、作品の購入ボタンを隠しています。これはほとんどの場合、しかし、2人の人が同時に作品を観ると、彼らは両方を購入することができます。これは、ページがリロードされるまで、他のページのピースのステータスが更新されないためです。特定のモデルパラメータでストライプ購入のみを許可します

私のリクエスト:誰かが購入する直前に、作品のステータスが1であることを確認する方法を探したいと思います。それが1ではない場合は、すでに購入されているというフラッシュのメッセージが表示されます。これにより、ユーザーは請求されず、chargeが作成されなくなります。ここで

は私の料金コントローラです:

class ChargesController < ApplicationController 
    def create 

    piece = Piece.find(params[:piece_id]) 

    customer = Stripe::Customer.create(
     :email => params[:stripeEmail], 
     :source => params[:stripeToken] 
    ) 

    charge = Stripe::Charge.create(
     :customer => customer.id, 
     :amount  => piece.total_price_in_cents, 
     :description => piece.title, 
     :currency => 'usd' 
    ) 

    purchase = Purchase.create(
     customer_email: params[:stripeEmail], 

     total_transaction: piece.total_price, 
     stripe_fee: piece.stripe_fee, 
     taxes: piece.taxes, 
     artist_cut: piece.artist_cut, 
     charity_cut: piece.charity_cut, 
     our_cut: piece.our_cut, 

     currency: charge.currency, 
     card: params[:stripeToken], 
     description: charge.description, 
     customer_id: customer.id, 
     piece_id: piece.id, 

     customer_name: params[:stripeShippingName], 
     customer_address_line_1: params[:stripeShippingAddressLine1], 
     customer_city: params[:stripeShippingAddressCity], 
     customer_state: params[:stripeShippingAddressState], 
     customer_zip_code: params[:stripeShippingAddressZip], 
     customer_country: params[:stripeShippingAddressCountry], 

     seller_name: piece.user.name, 
     seller_email: piece.user.email, 
     seller_address_line_1: piece.user.address_line_1, 
     seller_address_line_2: piece.user.address_line_2, 
     seller_city: piece.user.city, 
     seller_state: piece.user.state, 
     seller_zip_code: piece.user.zip_code 

    ) 

    purchase.ship_by = purchase.created_at + 7.days 
    purchase.arrive_by = purchase.created_at + 21.days 
    purchase.save! 

    piece.status = 3 
    piece.save! 
    redirect_to pieces_path, notice: "Thanks for buying #{piece.title} for $#{'%.2f' % piece.total_price}. You should get an email shortly." 

    rescue Stripe::CardError => e 
     flash[:error] = e.message 
     redirect_to new_charge_path 
    end 

    end 

そしてここで、その上にストライプ購入ボタンを持っている作品のための私のショーのページで、次のとおりです。

<div class="container"> 
    <div class="row"> 
    <div class="col-md-offset-2 col-md-8"> 
    <div class="panel panel-default"> 
    <div class="panel-body"> 

     <!-- Stripe Form --> 
     <% if current_user != @piece.user && @piece.status == 1 %> 
     <%= form_tag charges_path, id: 'chargeForm' do %> 
       <script src="https://checkout.stripe.com/checkout.js"></script> 
       <%= hidden_field_tag 'stripeToken' %> 
       <%= hidden_field_tag 'stripeEmail' %> 


       <button id="btn-buy-show" type="button" class="btn btn-success btn-lg btn-block">Buy for $<%= number_with_precision(@piece.total_price, :precision => 2, :delimiter => ',')%></button> 
       <script> 
       var handler = StripeCheckout.configure({ 
       key: '<%= Rails.configuration.stripe[:publishable_key] %>', 
       shippingAddress: true, 
       token: function(token, arg) { 
        document.getElementById("stripeToken").value = token.id; 
        document.getElementById("stripeEmail").value = token.email; 
        document.getElementById("chargeForm").submit(); 
       } 
       }); 
       document.getElementById('btn-buy-show').addEventListener('click', function(e) { 
       handler.open({ 
        name: 'Metallic Palette', 
        description: '<%= @piece.title %> ($<%= number_with_precision(@piece.total_price, :precision => 2, :delimiter => ',')%>)', 
        amount: document.getElementById("amount").value 
       }); 
       e.preventDefault(); 
      }) 
      </script> 
      <% end %> 
     <% end %> 

     <% if @piece.status == 3 %> 
     <p>This piece has already been bought. 
      <% if current_user == @piece.user || admin_user_signed_in? %> 
      <%= render 'pieces/purchase_details' %> 
      <% end %> 
     </p> 
     <% end %> 
    </div> 
    </div> 
</div> 

はありがとうみんなそんなに。

答えて

0

あなたはそれをチェックする必要があります:)

def create 
    piece = Piece.find(params[:piece_id]) 

    if piece.status != 1 
    flash[:error] = 'Piece is not available :(' 
    return redirect_to peaces_path # or whatever 
    end 

    ... 
end 

しかし、いくつかは、あなたのための示唆: 1)あなたのコード内の数字は使用しないでください。定数(Piece::AVAILABLEなど)とメソッド(piece.available?)を作成するか、enumを使用してください。

2)フォームオブジェクトを抽出する - あなたのコントローラーに大きなメソッドを持っていたくない場合は、将来的に多くの問題が発生します。それを分離してサービスに抽出すれば、それははるかにテスト可能で、予測可能で、更新可能になります。

3)Piece.findを抽出し、before_filtersの状態チェックを行います。

関連する問題