触发 rails 控制器功能 - Paypal 网站标准 IPN

Posted

技术标签:

【中文标题】触发 rails 控制器功能 - Paypal 网站标准 IPN【英文标题】:Trigger rails controller function - Paypal Website Standard IPN 【发布时间】:2016-10-25 06:16:18 【问题描述】:

我的应用中有一个 PaymentNotificationsController 中的 Paypal IPN。但是,一些变量取决于购物车中的商品数量,所以我想在创建 PaymentNotification 之前提取它们。

到目前为止,我有:

class PaymentNotificationsController < ApplicationController
  protect_from_forgery except: [:create]
     def create
       PaymentNotification.create!(params: params, 
       item_number: params[:item_number], item_name: params[:item_name], quantity: params[:quantity] 
       render nothing: true
     end
end

但是,当通知来自 PayPal 时,它以item_name1, item_number1, quantity1, item_name2, item_number2, quantity2 等形式出现。 即使它只是一项,它也会以item_name1, item_number1, quantity1, option1 等形式出现。

我有这个函数来尝试提取变量,但我不知道如何触发这个函数。我尝试在控制器顶部使用before_action,但它不起作用。返回wrong number of arguments(0 for 1)

ITEM_PARAM_PREFIXES = ["item_name", "item_number", "quantity"]

def extract_ipn_items_params(params)
  item_params = []

  loop do
    item_num_to_test = item_params.length + 1
    item_num_suffix = item_num_to_test.to_s
    possible_param_name = ITEM_PARAM_PREFIXES[0] + item_num_suffix
    if params.include?(possible_param_name)
      this_item_params = 
      ITEM_PARAM_PREFIXES.each do |prefix|
        this_item_params[prefix] = params[prefix + item_num_suffix]
      end
      item_params.push this_item_params
    else
      return item_params
    end
  end
end

所以我在问,我如何触发函数来提取变量并将它们放入购物车中每个项目的 params[:item_number]、params[:item_name]、params[:quantity] 中,如果有两个项目,是否会创建两个单独的 PaymentNotification?

注意:两种方法都在同一个PaymentNotificationsController中。

任何帮助将不胜感激。提前致谢!

【问题讨论】:

【参考方案1】:

我假设您的方法 extract_ipn_items_params 已经获取了您需要的数据,您可以删除该方法的 params 参数,因为参数始终在控制器的 actions/methods 中可用。

ITEM_PARAM_PREFIXES = ["item_name", "item_number", "quantity"]

def extract_ipn_items_params
    mod_params = Hash.new|k, v| k[v] =  

    ITEM_PARAM_PREFIXES.each do |item_data_key|
        key_tracker = 1
        loop do
            current_key = (item_data_key + key_tracker.to_s).to_sym
            if params.include? current_key
                mod_params[key_tracker][item_data_key] = params[current_key]
            else
                break
            end
            key_tracker += 1
        end
    end
    mod_params
end

该方法返回一个哈希值,例如:

1 =&gt; item_name: 'Item 1', item_number: 1084, quantity: 15,如果您为用户设置了嵌套属性,我认为您应该能够做类似的事情,虽然不太确定,但应该可以:

user.update(payment_notifications_attributes: extract_ipn_items_params)

让我知道这是否适合你。

更新

根据 Github Gist,我想出了以下几点:

class PaymentNotificationsController < ApplicationController
  protect_from_forgery except: [:create]

  ITEM_PARAM_PREFIXES = ["item_name", "item_number", "quantity", "option_name"]


   def create
    extract_ipn_items_params.each do |key, values|
      # this approach loops through all the returned results, nested attributes may help abstract this though
        PaymentNotification.create(values)  
        render nothing: true
    end

  def details
    # params.extract_ipn_items_params #this doesn't exist as params is an instance of ActionController::Parameters
    PaymentNotification.update_attributes(line_item_id: params[:item_number], product_title: params[:item_name], option_name: params[:option_name], quantity: params[:quantity])
  end

  private

    def additional_attributes
      # create this for additional merge attributes. A better place for these would be the parent of this
      
        params: params, 
        cart_id: params[:invoice], 
        status: params[:payment_status], 
        transaction_id: params[:txn_id], 
        first_name: params[:first_name], 
        last_name: params[:last_name], 
        email: params[:payer_email], 
        address_name: params[:address_name], 
        address_street: params[:address_street], 
        address_city: params[:address_city], 
        address_state: params[:address_state], 
        address_zip: params[:address_zip], 
        address_country: params[:address_country]
      
    end

    def extract_ipn_items_params
      mod_params = Hash.new|k, v| k[v] = .merge(additional_attributes) 

      ITEM_PARAM_PREFIXES.each do |item_data_key|
          key_tracker = 1
          loop do
              current_key = (item_data_key + key_tracker.to_s).to_sym
              if params.include? current_key
                  mod_params[key_tracker][item_data_key] = params[current_key]
              else
                  break
              end
              key_tracker += 1
          end
      end
      mod_params
    end

end

如果这能解决您的问题,请告诉我。

【讨论】:

感谢您的回答。因此,如果我只是在 create 操作之前添加它,它会在运行创建之前提取项目?这是文件的样子 >> https://www.dropbox.com/s/2f508296wb378wc/sublime.png?dl=0 数据来自paypal到PaymentNotificationsController 不,在创建之前运行它不会影响参数 ATM,因为您没有更改参数的状态,只是提取您需要的属性。在这种情况下,item_nameitem_numberquantity。现在有几种方法可以将这些记录插入数据库,其中包含嵌套参数。您能否创建一个显示您的 PaymentNotificationsController 的 Github Gist,以便我可以使用另一种使用循环插入记录的方法来更新我的答案 刚试过但没用>>gist.github.com/d1t/7f3a9451500579da617134468beeca96 附上模型,让大家了解整个画面 非常感谢!它可以工作,但我需要在创建时填充变量,因为我在模型中有 after_create 回调。我尝试使用 fetch 从哈希中删除每个单独的变量,但很挣扎。有时间请看>>https://gist.github.com/d1t/7f3a9451500579da617134468beeca96【参考方案2】:

您应该有 payment_id 以便您可以使用 gem 'paypal-sdk-rest' 找到它

payment = PayPal::SDK::REST::Payment.find payment_id

然后您可以在支付对象中看到所有详细信息

【讨论】:

我已经可以看到细节了。当通知到来时,它会创建除变量之外的其他变量:item_name、item_number 等,因为 PayPal 将它们作为 item_name1、item_number1 发送。在创建之前,我只需要一种 Rails 方式从通知中提取它们! 我也在使用 Paypal 网站标准,而不是 REST API

以上是关于触发 rails 控制器功能 - Paypal 网站标准 IPN的主要内容,如果未能解决你的问题,请参考以下文章

在 Rails 控制器中包含库时,Paypal SDK Ruby 错误

Rails PayPal Checkout SDK 在视图而不是控制器中存储请求正文

Rails PayPal IPN activemerchant 控制器 rspec 测试

Rails:Paypal 端点 /v2/checkout/orders 返回 http 401

金额无效 paypal_adaptive gem rails

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