使用 Ruby on Rails form_for 和控制器/方法绑定 PayPal 智能按钮?

Posted

技术标签:

【中文标题】使用 Ruby on Rails form_for 和控制器/方法绑定 PayPal 智能按钮?【英文标题】:Tying in the PayPal smart buttons with a Ruby on Rails form_for and controller/method? 【发布时间】:2019-09-03 21:59:37 【问题描述】:

我的智能按钮在沙盒中“工作”,但我想不出任何方法可以将智能按钮成功附加到创建订单的订单表单上。使用 Stripe Elements,它非常即插即用,因为它在页面上并且是表单本身的一部分,但是使用带有重定向的 PayPal,我似乎想不出办法。

这是否需要 javascript 或者我可以在没有它的情况下执行此操作,除了已经存在的内容吗?

表格:

<%= form_for(@order, url: listing_orders_path([@listing, @listing_video]), html: id: "payment_form-4" ) do |form| %>

   <%= form.label :name, "Your Name", class: "form-label" %>
   <%= form.text_field :name, class: "form-control", required: true, placeholder: "John" %>
#stripe code here (not important)
<%= form.submit %>
  <div id="paypal-button-container"></div>

<!-- Include the PayPal JavaScript SDK -->
<script src="https://www.paypal.com/sdk/js?client-id=sb&currency=USD"></script>

  <script>
    // Render the PayPal button into #paypal-button-container
    paypal.Buttons(

        // Set up the transaction
        createOrder: function(data, actions) 
            return actions.order.create(
                purchase_units: [
                    amount: 
                        value: <%= @listing.listing_video.price %>
                    
                ]
            );
        ,

        // Finalize the transaction
        onApprove: function(data, actions) 
            return actions.order.capture().then(function(details) 
                // Show a success message to the buyer
                alert('Transaction completed by ' + details.payer.name.given_name + '!');
            );
        


    ).render('#paypal-button-container');
</script>

在控制器中创建方法:

require 'paypal-checkout-sdk'
client_id = Rails.application.credentials[Rails.env.to_sym].dig(:paypal, :client_id)
client_secret = Rails.application.credentials[Rails.env.to_sym].dig(:paypal, :client_secret)
# Creating an environment
environment = PayPal::SandboxEnvironment.new(client_id, client_secret)
client = PayPal::PayPalHttpClient.new(environment)

@amount_paypal = (@listing.listing_video.price || @listing.listing_tweet.price)
request = PayPalCheckoutSdk::Orders::OrdersCreateRequest::new
request.request_body(
  
    intent: 'AUTHORIZE',
    purchase_units: [
      
        amount: 
          currency_code: 'USD',
          value: "#@amount_paypal"
        
      
    ]
  
)

begin
  # Call API with your client and get a response for your call
  response = client.execute(request)

  # If call returns body in response, you can get the deserialized version from the result attribute of the response
  order = response.result
  puts order
  @order.paypal_authorization_token = response.id
rescue BraintreeHttp::HttpError => ioe
  # Something went wrong server-side
  puts ioe.status_code
  puts ioe.headers['debug_id']
end

如何将 PayPal 智能按钮与表单绑定,以便付款完成后,如果成功,它会创建订单?

更新::::::::

创建了一个 PaypalPayments 控制器和模型:

控制器:

  def create
    @paypal_payment = PaypalPayment.new
    @listing = Listing.find_by(params[:listing_id])  

    require 'paypal-checkout-sdk'
    client_id = "#Rails.application.credentials[Rails.env.to_sym].dig(:paypal, :client_id)"
    client_secret = "#Rails.application.credentials[Rails.env.to_sym].dig(:paypal, :client_secret)"
    # Creating an environment
    environment = PayPal::SandboxEnvironment.new(client_id, client_secret)
    client = PayPal::PayPalHttpClient.new(environment)

    @amount_paypal = @listing.listing_video.price
    request = PayPalCheckoutSdk::Orders::OrdersCreateRequest::new
    @paypal_payment = request.request_body(
                            intent: "AUTHORIZE",
                            purchase_units: [
                                
                                    amount: 
                                        currency_code: "USD",
                                        value: "#@amount_paypal"
                                    
                                
                            ]
                          )

    begin
        # Call API with your client and get a response for your call
        response = client.execute(request)

        # If call returns body in response, you can get the deserialized version from the result attribute of the response
        order = response.result
        puts order
        # @order.paypal_authorization_token = response.id
    rescue BraintreeHttp::HttpError => ioe
        # Something went wrong server-side
        puts ioe.status_code
        puts ioe.headers["debug_id"]
    end

    # if @paypal_payment.create
    #   render json: success: true
    # else
    #   render json: success: false
    # end

  end

视图中的Javascript:

paypal.Buttons(

                                      createOrder: function() 
                                        return fetch('/paypal_payments', 
                                          method: 'post',
                                          headers: 
                                            'content-type': 'application/json'
                                          
                                        ).then(function(res) 
                                          return res.json();
                                        ).then(function(data) 
                                          return data.orderID;
                                        );
                                      ,



                                      onApprove: function(data) 
                                        return fetch('/orders', 
                                          method: 'post',
                                          headers: 
                                            'content-type': 'application/json'
                                          ,
                                          body: JSON.stringify(
                                            orderID: data.orderID
                                          )
                                        ).then(function(res) 
                                          return res.json();
                                        ).then(function(details) 
                                          alert('Authorization created for ' + details.payer_given_name);
                                        );
                                      ,


                                  ).render('#paypal-button-container');

这样,paypal 框会出现,但在 CMD 中加载后立即消失:

#<OpenStruct id="1Pxxxxxxx394U", links=[#<OpenStruct href="https://api.sandbox.paypal.com/v2/checkout/orders/1P0xxxxxxx394U", rel="self", method="GET">, #<OpenStruct href="https://www.sandbox.paypal.com/checkoutnow?token=1P07xxxxxxx94U", rel="approve", method="GET">, #<OpenStruct href="https://api.sandbox.paypal.com/v2/checkout/orders/1Pxxxxxxx4U", rel="update", method="PATCH">, #<OpenStruct href="https://api.sandbox.paypal.com/v2/checkout/orders/1P07xxxxxxx394U/authorize", rel="authorize", method="POST">], status="CREATED">
No template found for PaypalPaymentsController#create, rendering head :no_content
Completed 204 No Content in 2335ms (ActiveRecord: 15.8ms)

【问题讨论】:

这甚至是一种方法吗?这是什么控制器动作? 那在 create 方法中。它有大量的代码,所以我只输入了贝宝部分。我不确定如何将它们联系在一起。我需要重定向到 onApprove: function(data, actions) 上的 create 方法吗? 我真的不明白这一点。我需要以某种方式将定价信息从 createOrder: function(data, actions) 的视图中删除到控制器创建方法(或其他具有上述创建代码的方法)。您是否已将智能按钮集成到 rails 应用程序? 【参考方案1】:

我没有使用智能按钮。但是,您不应该在创建操作中有“大量代码”。如果您遵循 MVC 和 rails 约定。您似乎需要一个单独的控制器操作来处理与创建操作分开的付款授权。但是,如果您可以在您的 javascript 中达到这一点,这里是您如何将数据从 paypal javascript 发送回您的控制器的示例,这将需要一些工作,但希望它为您指明正确的方向:

// Finalize the transaction
onApprove: function(data, actions) 
  return actions.order.capture().then(function(details) 
    // Show a success message to the buyer
    alert('Transaction completed by ' + details.payer.name.given_name + '!');
   // here is where you should send info to your controller action via ajax.
     $.ajax(
        type: "POST",
        url: "/orders",
        data: data,
        success: function(data) 
          alert(data); // or whatever you wanna do here
          return false;
        ,
        error: function(data) 
          alert(data); // or something else
          return false;
        
     );
  );

【讨论】:

我会试试这个。还有更多的代码,我的意思是与创建订单本身有关的逻辑,而不是贝宝的东西 所以我从 PayPal 文档的信息中做了类似的事情,但我仍然没有找到任何方法将其与表单联系起来。因为我的订单创建是基于表单提交而不是购物车。到目前为止,是的,我可以创建支付给贝宝的付款,但是为了使用 POST 创建订单,我需要从表单中提交它......你知道有一种方法,所以当 onApprove 时,我可以有某种需要表单输入的事件? OP 已更新。在这里“靠近”但不起作用 @uno 你找到解决方案了吗?【参考方案2】:

这很可能为时已晚,但我会添加对我有用的东西。 您需要将响应 ID 作为 json 对象返回给 PayPal 脚本。您需要做的就是像这样更新您的创建函数:

...
begin
    # Call API with your client and get a response for your call
    response = client.execute(request)

    # If call returns body in response, you can get the deserialized version from the result attribute of the response
    order = response.result
    render json:  orderID: order.id 
    # @order.paypal_authorization_token = response.id
rescue BraintreeHttp::HttpError => ioe
    # Something went wrong server-side
    puts ioe.status_code
    puts ioe.headers["debug_id"]
end
...

【讨论】:

以上是关于使用 Ruby on Rails form_for 和控制器/方法绑定 PayPal 智能按钮?的主要内容,如果未能解决你的问题,请参考以下文章

不允许用户在 ruby​​ on rails 中提交带有空字段的表单

在 ruby​​ on rails 中以一对多关系创建新记录

Ruby on Rails 3 表单中的 _snowman 参数有啥用?

Ruby on Rails:提交按下时的警报按钮

Ruby on Rails 表单中的 select 和 onChange

Ruby on Rails 開發秘籍 | Ruby on Rails 快速入門