I have a Order model, and I'm trying to move the business logic into Order instead of OrderController. Here's the problem I'm facing:
class Api::V1::OrdersController < ApplicationController
before_action :authenticate_with_token!, only: [:create, :show, :index]
respond_to :json
def create
order = current_retailer.orders.build
order.checkout_cash(current_retailer, params[:order][:product_ids_with_quantities], order_params[:member_external_id])
puts order
if order.key?(:errors)
render json: order, status: 422
else
render json: order, status: 201
end
puts "HEY!!!"
puts order.inspect
end
so the order.checkout_cash
method is the business logic I'm implementing in Order model.
I have to know if it's a valid or it returns an error.
Here's my code in Order model:
def checkout_cash(current_retailer, product_ids_with_quantities, member_external_id)
puts "CASH!!!"
order = current_retailer.orders.build
order.payment_method = "cash"
order.build_placements(product_ids_with_quantities)
order.set_total_charge!
if member_external_id.blank?
return order
else
member = Member.find_by(member_external_id: external_id)
if member
order.add_points(member)
return order
else
return {errors: "Not a member or wrong membership id. Please register first"}
end
end
In OrderController the line
if order.key?(:
results in:
NoMethodError:
undefined method `key?' for #<Order:0x007fb7a29ec260>
I'm sure it's because I'm calling a function on hash, on a Order object. How should I do this in Rails?
Now:
def create
order = current_retailer.orders.build
checkout_result = order.checkout_cash(current_retailer, params[:order][:product_ids_with_quantities], order_params[:member_external_id])
puts order
if checkout_result.key?(:errors)
render json: order, status: 422
else
order.save!
order.reload
render json: order, status: 201
end
is getting:
1) Api::V1::OrdersController POST #create create with default total_charge return 0 as total_charge
Failure/Error: get :create, retailer_id: @retailer, order: {product_ids_with_quantities: []}
NoMethodError:
undefined method `key?' for #<Order:0x007ff69244fb70>
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/activemodel-4.2.0/lib/active_model/attribute_methods.rb:433:in `method_missing'
# ./app/controllers/api/v1/orders_controller.rb:11:in `create'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/actionpack-4.2.0/lib/action_controller/metal/implicit_render.rb:4:in `send_action'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/actionpack-4.2.0/lib/abstract_controller/base.rb:198:in `process_action'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/actionpack-4.2.0/lib/action_controller/metal/rendering.rb:10:in `process_action'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/actionpack-4.2.0/lib/abstract_controller/callbacks.rb:20:in `block in process_action'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/activesupport-4.2.0/lib/active_support/callbacks.rb:117:in `call'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/activesupport-4.2.0/lib/active_support/callbacks.rb:117:in `call'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/activesupport-4.2.0/lib/active_support/callbacks.rb:151:in `block in halting_and_conditional'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/activesupport-4.2.0/lib/active_support/callbacks.rb:234:in `call'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/activesupport-4.2.0/lib/active_support/callbacks.rb:234:in `block in halting'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/activesupport-4.2.0/lib/active_support/callbacks.rb:169:in `call'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/activesupport-4.2.0/lib/active_support/callbacks.rb:169:in `block in halting'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/activesupport-4.2.0/lib/active_support/callbacks.rb:92:in `call'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/activesupport-4.2.0/lib/active_support/callbacks.rb:92:in `_run_callbacks'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/activesupport-4.2.0/lib/active_support/callbacks.rb:734:in `_run_process_action_callbacks'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/activesupport-4.2.0/lib/active_support/callbacks.rb:81:in `run_callbacks'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/actionpack-4.2.0/lib/abstract_controller/callbacks.rb:19:in `process_action'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/actionpack-4.2.0/lib/action_controller/metal/rescue.rb:29:in `process_action'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/actionpack-4.2.0/lib/action_controller/metal/instrumentation.rb:31:in `block in process_action'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/activesupport-4.2.0/lib/active_support/notifications.rb:164:in `block in instrument'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/activesupport-4.2.0/lib/active_support/notifications/instrumenter.rb:20:in `instrument'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/activesupport-4.2.0/lib/active_support/notifications.rb:164:in `instrument'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/actionpack-4.2.0/lib/action_controller/metal/instrumentation.rb:30:in `process_action'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/actionpack-4.2.0/lib/action_controller/metal/params_wrapper.rb:250:in `process_action'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/activerecord-4.2.0/lib/active_record/railties/controller_runtime.rb:18:in `process_action'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/actionpack-4.2.0/lib/abstract_controller/base.rb:137:in `process'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/actionview-4.2.0/lib/action_view/rendering.rb:30:in `process'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/actionpack-4.2.0/lib/action_controller/test_case.rb:629:in `process'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/actionpack-4.2.0/lib/action_controller/test_case.rb:65:in `process'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/devise-3.5.1/lib/devise/test_helpers.rb:19:in `block in process'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/devise-3.5.1/lib/devise/test_helpers.rb:72:in `catch'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/devise-3.5.1/lib/devise/test_helpers.rb:72:in `_catch_warden'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/devise-3.5.1/lib/devise/test_helpers.rb:19:in `process'
# /opt/twitter/rvm/gems/ruby-1.9.3-p551/gems/actionpack-4.2.0/lib/action_controller/test_case.rb:505:in `get'
# ./spec/controllers/api/v1/orders_controller_spec.rb:37:in `block (4 levels) in <top (required)>'
You're not using the checkout_cash
return value. The correct code should be:
checkout_result = order.checkout_cash(current_retailer, params[:order][:product_ids_with_quantities], order_params[:member_external_id])
if checkout_result.key?(:errors)
render json: order, status: 422
else
render json: order, status: 201
end
UPDATE:
I misread the checkout_cash
method. I'd advise you against allowing a method to return different classes depending on the input, it forces the caller to know the method's internal behaviour. Since you're not using the order
object which inside checkout_cash
, you could simply return a empty hash in case of success.
However, I think this method has too many responsibilities that don't concern to the Order
class. You could write a form object to handle this custom validation and keep your model simple. Check this great article: http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/ .
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.