我正在使用Ruby on Rails 4和Spree,我必须使用外部支付服务 - liqpay - https://www.liqpay.com/,因此我创建了自定义网关,自定义Checkout控制器和用于liqpay回调的Created控制器。付款完成后,我有预先最后一页和一个“完成订单”的按钮,一切似乎都很好。但是当我点击这个但是我有一个错误时,这就是日志中的内容
ActiveRecord::UnknownAttributeError (unknown attribute: server):
activerecord (4.0.6) lib/active_record/attribute_assignment.rb:47:in `rescuein _assign_attribute'
activerecord (4.0.6) lib/active_record/attribute_assignment.rb:42:in `_assign_attribute'
activerecord (4.0.6) lib/active_record/attribute_assignment.rb:29:in `block in assign_attributes'
activerecord (4.0.6) lib/active_record/attribute_assignment.rb:23:in `each'
activerecord (4.0.6) lib/active_record/attribute_assignment.rb:23:in `assign_attributes'
activerecord (4.0.6) lib/active_record/core.rb:469:in `init_attributes'
activerecord (4.0.6) lib/active_record/core.rb:185:in `initialize'
activerecord (4.0.6) lib/active_record/inheritance.rb:30:in `new'
activerecord (4.0.6) lib/active_record/inheritance.rb:30:in `new'
spree_core (2.2.4) app/models/spree/gateway.rb:25:in `provider'
spree_core (2.2.4) app/models/spree/gateway.rb:2:in `purchase'
spree_core (2.2.4) app/models/spree/payment/processing.rb:158:in `block in gateway_action'
spree_core (2.2.4) app/models/spree/payment/processing.rb:191:in `protect_from_connection_error'
spree_core (2.2.4) app/models/spree/payment/processing.rb:155:in `gateway_action'
spree_core (2.2.4) app/models/spree/payment/processing.rb:33:in `purchase!'
spree_core (2.2.4) app/models/spree/payment/processing.rb:10:in `process!'
spree_core (2.2.4) app/models/spree/order.rb:391:in `block in process_payments!'
spree_core (2.2.4) app/models/spree/order.rb:388:in `each'
spree_core (2.2.4) app/models/spree/order.rb:388:in `process_payments!'
spree_core (2.2.4) app/models/spree/order/checkout.rb:74:in `block (2 levels) in define_state_machine!'
state_machine (1.2.0) lib/state_machine/eval_helpers.rb:79:in `call'
state_machine (1.2.0) lib/state_machine/eval_helpers.rb:79:in `evaluate_method'
state_machine (1.2.0) lib/state_machine/callback.rb:191:in `block in run_methods'
state_machine (1.2.0) lib/state_machine/callback.rb:190:in `each'
state_machine (1.2.0) lib/state_machine/callback.rb:190:in `run_methods'
state_machine (1.2.0) lib/state_machine/callback.rb:159:in `call'
state_machine (1.2.0) lib/state_machine/transition.rb:420:in `before'
state_machine (1.2.0) lib/state_machine/transition.rb:246:in `block in run_callbacks'
state_machine (1.2.0) lib/state_machine/transition.rb:348:in `block in pausable'
state_machine (1.2.0) lib/state_machine/transition.rb:348:in `catch'
state_machine (1.2.0) lib/state_machine/transition.rb:348:in `pausable'
state_machine (1.2.0) lib/state_machine/transition.rb:246:in `run_callbacks'
state_machine (1.2.0) lib/state_machine/transition_collection.rb:127:in `run_callbacks'
state_machine (1.2.0) lib/state_machine/transition_collection.rb:63:in `block (2 levels) in perform'
state_machine (1.2.0) lib/state_machine/transition_collection.rb:63:in `catch'
state_machine (1.2.0) lib/state_machine/transition_collection.rb:63:in `block in perform'
state_machine (1.2.0) lib/state_machine/transition_collection.rb:182:in `block in within_transaction'
spree_core (2.2.4) app/models/spree/gateway.rb:25:in `provider'
spree_core (2.2.4) app/models/spree/gateway.rb:2:in `purchase'
spree_core (2.2.4) app/models/spree/payment/processing.rb:158:in `block in gateway_action'
spree_core (2.2.4) app/models/spree/payment/processing.rb:191:in `protect_from_connection_error'
spree_core (2.2.4) app/models/spree/payment/processing.rb:155:in `gateway_action'
spree_core (2.2.4) app/models/spree/payment/processing.rb:33:in `purchase!'
spree_core (2.2.4) app/models/spree/payment/processing.rb:10:in `process!'
spree_core (2.2.4) app/models/spree/order.rb:391:in `block in process_payments!'
spree_core (2.2.4) app/models/spree/order.rb:388:in `each'
spree_core (2.2.4) app/models/spree/order.rb:388:in `process_payments!'
spree_core (2.2.4) app/models/spree/order/checkout.rb:74:in `block (2 levels) in define_state_machine!'
state_machine (1.2.0) lib/state_machine/eval_helpers.rb:79:in `call'
state_machine (1.2.0) lib/state_machine/eval_helpers.rb:79:in `evaluate_method'
state_machine (1.2.0) lib/state_machine/callback.rb:191:in `block in run_methods'
state_machine (1.2.0) lib/state_machine/callback.rb:190:in `each'
state_machine (1.2.0) lib/state_machine/callback.rb:190:in `run_methods'
state_machine (1.2.0) lib/state_machine/callback.rb:159:in `call'
state_machine (1.2.0) lib/state_machine/transition.rb:420:in `before'
state_machine (1.2.0) lib/state_machine/transition.rb:246:in `block in run_callbacks'
state_machine (1.2.0) lib/state_machine/transition.rb:348:in `block in pausable'
state_machine (1.2.0) lib/state_machine/transition.rb:348:in `catch'
state_machine (1.2.0) lib/state_machine/transition.rb:348:in `pausable'
state_machine (1.2.0) lib/state_machine/transition.rb:246:in `run_callbacks'
state_machine (1.2.0) lib/state_machine/transition_collection.rb:127:in `run_callbacks'
state_machine (1.2.0) lib/state_machine/transition_collection.rb:63:in `block (2 levels) in perform'
state_machine (1.2.0) lib/state_machine/transition_collection.rb:63:in `catch'
state_machine (1.2.0) lib/state_machine/transition_collection.rb:63:in `block in perform'
state_machine (1.2.0) lib/state_machine/transition_collection.rb:182:in `block in within_transaction'
state_machine (1.2.0) lib/state_machine/transition.rb:227:in `block in within_transaction'
state_machine (1.2.0) lib/state_machine/machine.rb:1904:in `within_transaction'
state_machine (1.2.0) lib/state_machine/transition.rb:226:in `within_transaction'
state_machine (1.2.0) lib/state_machine/transition_collection.rb:181:in `within_transaction'
state_machine (1.2.0) lib/state_machine/transition_collection.rb:62:in `perform'
state_machine (1.2.0) lib/state_machine/transition.rb:219:in `perform'
state_machine (1.2.0) lib/state_machine/event.rb:172:in `fire'
state_machine (1.2.0) lib/state_machine/event.rb:247:in `block in add_actions'
state_machine (1.2.0) lib/state_machine/machine.rb:765:in `call'
state_machine (1.2.0) lib/state_machine/machine.rb:765:in `block (2 levels) in define_helper'
spree_frontend (2.2.4) app/controllers/spree/checkout_controller.rb:30:in `update'
actionpack (4.0.6) lib/action_controller/metal/implicit_render.rb:4:in `send_action'
actionpack (4.0.6) lib/abstract_controller/base.rb:189:in `process_action'
actionpack (4.0.6) lib/action_controller/metal/rendering.rb:10:in `process_action'
actionpack (4.0.6) lib/abstract_controller/callbacks.rb:18:in `block in process_action'
activesupport (4.0.6) lib/active_support/callbacks.rb:563:in `_run__4393275023746077082__process_action__callbacks'
activesupport (4.0.6) lib/active_support/callbacks.rb:80:in `run_callbacks'
actionpack (4.0.6) lib/abstract_controller/callbacks.rb:17:in `process_action'
actionpack (4.0.6) lib/action_controller/metal/rescue.rb:29:in `process_action'
actionpack (4.0.6) lib/action_controller/metal/instrumentation.rb:31:in `block in process_action'
activesupport (4.0.6) lib/active_support/notifications.rb:159:in `block in instrument'
activesupport (4.0.6) lib/active_support/notifications/instrumenter.rb:20:in `instrument'
activesupport (4.0.6) lib/active_support/notifications.rb:159:in `instrument'
actionpack (4.0.6) lib/action_controller/metal/instrumentation.rb:30:in `process_action'
actionpack (4.0.6) lib/action_controller/metal/params_wrapper.rb:250:in `process_action'
activerecord (4.0.6) lib/active_record/railties/controller_runtime.rb:18:in `process_action'
actionpack (4.0.6) lib/abstract_controller/base.rb:136:in `process'
actionpack (4.0.6) lib/abstract_controller/rendering.rb:44:in `process'
actionpack (4.0.6) lib/action_controller/metal.rb:195:in `dispatch'
actionpack (4.0.6) lib/action_controller/metal/rack_delegation.rb:13:in `dispatch'
actionpack (4.0.6) lib/action_dispatch/routing/route_set.rb:82:in `dispatch'
actionpack (4.0.6) lib/action_dispatch/routing/route_set.rb:50:in `call'
actionpack (4.0.6) lib/action_dispatch/journey/router.rb:71:in `block in call'
actionpack (4.0.6) lib/action_dispatch/journey/router.rb:59:in `each'
actionpack (4.0.6) lib/action_dispatch/journey/router.rb:59:in `call'
actionpack (4.0.6) lib/action_dispatch/routing/route_set.rb:676:in `call'
railties (4.0.6) lib/rails/engine.rb:511:in `call'
railties (4.0.6) lib/rails/railtie/configurable.rb:30:in `method_missing'
actionpack (4.0.6) lib/action_dispatch/journey/router.rb:71:in `block in call'
actionpack (4.0.6) lib/action_dispatch/journey/router.rb:59:in `each'
actionpack (4.0.6) lib/action_dispatch/journey/router.rb:59:in `call'
actionpack (4.0.6) lib/action_dispatch/routing/route_set.rb:676:in `call'
warden (1.2.3) lib/warden/manager.rb:35:in `block in call'
warden (1.2.3) lib/warden/manager.rb:34:in `catch'
warden (1.2.3) lib/warden/manager.rb:34:in `call'
rack (1.5.2) lib/rack/etag.rb:23:in `call'
rack (1.5.2) lib/rack/conditionalget.rb:35:in `call'
rack (1.5.2) lib/rack/head.rb:11:in `call'
actionpack (4.0.6) lib/action_dispatch/middleware/params_parser.rb:27:in `call'
actionpack (4.0.6) lib/action_dispatch/middleware/flash.rb:241:in `call'
rack (1.5.2) lib/rack/session/abstract/id.rb:225:in `context'
rack (1.5.2) lib/rack/session/abstract/id.rb:220:in `call'
actionpack (4.0.6) lib/action_dispatch/middleware/cookies.rb:486:in `call'
activerecord (4.0.6) lib/active_record/query_cache.rb:36:in `call'
activerecord (4.0.6) lib/active_record/connection_adapters/abstract/connection_pool.rb:626:in `call'
actionpack (4.0.6) lib/action_dispatch/middleware/callbacks.rb:29:in `block in call'
activesupport (4.0.6) lib/active_support/callbacks.rb:373:in `_run__2243693745465876108__call__callbacks'
activesupport (4.0.6) lib/active_support/callbacks.rb:80:in `run_callbacks'
actionpack (4.0.6) lib/action_dispatch/middleware/callbacks.rb:27:in `call'
actionpack (4.0.6) lib/action_dispatch/middleware/remote_ip.rb:76:in `call'
actionpack (4.0.6) lib/action_dispatch/middleware/debug_exceptions.rb:17:in `call'
actionpack (4.0.6) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
railties (4.0.6) lib/rails/rack/logger.rb:38:in `call_app'
railties (4.0.6) lib/rails/rack/logger.rb:20:in `block in call'
activesupport (4.0.6) lib/active_support/tagged_logging.rb:68:in `block in tagged'
activesupport (4.0.6) lib/active_support/tagged_logging.rb:26:in `tagged'
activesupport (4.0.6) lib/active_support/tagged_logging.rb:68:in `tagged'
railties (4.0.6) lib/rails/rack/logger.rb:20:in `call'
actionpack (4.0.6) lib/action_dispatch/middleware/request_id.rb:21:in `call'
rack (1.5.2) lib/rack/methodoverride.rb:21:in `call'
rack (1.5.2) lib/rack/runtime.rb:17:in `call'
activesupport (4.0.6) lib/active_support/cache/strategy/local_cache.rb:83:in `call'
rack (1.5.2) lib/rack/sendfile.rb:112:in `call'
railties (4.0.6) lib/rails/engine.rb:511:in `call'
railties (4.0.6) lib/rails/application.rb:97:in `call'
unicorn (4.8.3) lib/unicorn/http_server.rb:576:in `process_client'
unicorn (4.8.3) lib/unicorn/http_server.rb:670:in `worker_loop'
unicorn (4.8.3) lib/unicorn/http_server.rb:525:in `spawn_missing_workers'
unicorn (4.8.3) lib/unicorn/http_server.rb:140:in `start'
unicorn (4.8.3) bin/unicorn:126:in `<top (required)>'
/var/www/genetic_shop/shared/bundle/ruby/2.0.0/bin/unicorn:23:in `load'
/var/www/genetic_shop/shared/bundle/ruby/2.0.0/bin/unicorn:23:in `<main>'
完成付款后调用的控制器方法看起来非常简单
def payment_network_callback
if @order.paid?
@order.next
end
redirect_to checkout_state_path(@order.state)
end
支付状态改变后调用的和Api控制器方法是(看起来像黑客,但我不知道该怎么做)
def liqpay_api_callback
@order = Spree::Order.find params[:order_id]
@order.payments.create! source: Spree::LiqpayCheckout.create, amount: @order.total,
payment_method: Spree::PaymentMethod.where(type: 'Spree::Gateway::Liqpay').first if @order.payments.length == 0
if params[:status] == 'success' || params[:status] == 'sandbox'
@order.update_attribute :payment_state, 'paid'
head :ok
else
head :unprocessable_entity
end
rescue => e
logger.fatal e.class.to_s
logger.fatal e.to_s
logger.fatal e.backtrace.join('/n')
head :internal_server_error
end
那么,你有什么想法,'未知属性:服务器'是什么以及如何正确地做到这一点?谢谢!
答案 0 :(得分:2)
找到解决方案。可能它不是好风格,但它有效。所以,主要的逻辑是在CheckoutController装饰器中的回调方法,它在liqpay付款完成后被调用
def payment_network_callback
if @order.paid?
@order.payments.first.process!
@order.deliver_order_confirmation_email
@order.next
@order.finalize!
session[:order_id] = nil
end
redirect_to "/orders/#{@order.number}"
end
还有另一种方法 - 我的应用程序API方法,liqpay在paiment更改它在另一个控制器中的状态后调用它
def liqpay_api_callback
@order = Spree::Order.find params[:order_id]
sign = get_callback_sign(params[:amount], params[:order_id], params[:status], params[:transaction_id], params[:sender_phone])
@order.payments.create! source: Spree::LiqpayCheckout.create, amount: @order.total,
payment_method: Spree::PaymentMethod.where(type: 'Spree::Gateway::Liqpay').first if @order.payments.length == 0
sign[-1]=''
if (params[:status] == 'success' || params[:status] == 'sandbox') && (sign.eql? params[:signature])
@order.update_attribute :payment_state, 'paid'
head :ok
else
head :unprocessable_entity
end
rescue => e
logger.fatal e.class.to_s
logger.fatal e.to_s
logger.fatal e.backtrace.join('/n')
head :internal_server_error
end
end
这就是Gateway的样子
module Spree
class Gateway::Liqpay < Gateway
attr_accessor :server, :test_mode
preference :server,:string, default: 'test'
preference :test_mode, :boolean, default: true
def provider
@provider = self
end
def purchase(amount, source, options = {})
Class.new do
def success?; true; end
def authorization; nil; end
end.new
end
def auto_capture?
true
end
def payment_profiles_supported?
true
end
def provider_class
self.class
end
def method_type
'liqpay'
end
end
end