2
\$\begingroup\$

I'm working on a Rails application that has a lot of logic in the controller that should be in the model. In the app/controllers/customers_controller.rb#create there is logic to create stripe cc info for the customer. I think this should be in the model.

How can I move this logic into the model and still handle any exceptions in the controller?

app/controllers/customers_controller.rb

def create
 ...
 card = {
 'object' => 'card', 'number' => card_number, 'exp_month' => card_expire_month, 'exp_year' => card_expire_year,
 'cvc' => card_cvc, 'address_zip' => parms['zipcode'], 'name' => "#{parms['first_name']} #{parms['last_name']}",
 'address_line1' => parms['street_address_1'], 'address_state' => parms['state'],
 'address_line2' => parms['street_address_2'], 'address_city' => parms['city']
 }
 begin
 resp = Stripe::Customer.create(
 description: 'Customer for DoctorNow',
 metadata: { customer_id: @customer.id },
 email: @customer.email,
 source: card)
 @customer.assign_attributes(
 stripe_customer_id: resp['id'],
 stripe_card_id: resp['sources']['data'][0]['id'],
 stripe_card_last4: resp['sources']['data'][0]['last4'],
 stripe_card_type: resp['sources']['data'][0]['brand']
 )
 event('card_preauth', 'customer_id', @customer.id)
 rescue Stripe::CardError => e
 @err = stripe_error(e, 'creating_card_card_error', 0)
 render :err_show, status: :payment_required, json: @err
 event('card_preauth_failed', 'customer_id', @customer.id)
 return
 rescue Stripe::InvalidRequestError => e
 @err = stripe_error(e, 'create_card_invalid', 0)
 event('card_preauth_failed', 'customer_id', @customer.id)
 render :err_show, status: :payment_required, json: @err
 return
 rescue Stripe::AuthenticationError => e
 @err = stripe_error(e, 'create_card_authentication', 0)
 event('card_preauth_failed', 'customer_id', @customer.id)
 render :err_show, status: :payment_required, json: @err
 return
 rescue Stripe::APIConnectionError => e
 @err = stripe_error(e, 'create_card_connect', 0)
 event('card_preauth_failed', 'customer_id', @customer.id)
 render :err_show, status: :payment_required, json: @err
 return
 rescue Stripe::StripeError => e
 @err = stripe_error(e, 'create_card_stripe', 0)
 event('card_preauth_failed', 'customer_id', @customer.id)
 render :err_show, status: :payment_required, json: @err
 return
 rescue => e
 @err = stripe_error(e, 'create_card_generic', 0)
 render :err_show, status: :payment_required, json: @err
 event('card_preauth_failed', 'customer_id', @customer.id)
 return
 end
 ...
end
200_success
145k22 gold badges190 silver badges478 bronze badges
asked Jul 22, 2015 at 14:55
\$\endgroup\$
2
  • \$\begingroup\$ Where would the Stripe::*Error's be thrown from? Inside @customer.assign_attributes(...) or from event(...)? \$\endgroup\$ Commented Jul 23, 2015 at 18:01
  • \$\begingroup\$ @GregBurghardt Stripe::Customer.create \$\endgroup\$ Commented Jul 23, 2015 at 19:10

2 Answers 2

2
\$\begingroup\$

I prefer @Unixmoney solutin, I would just change the way you handle error, or better said use a block to shorter the perform method

 def perform
 handle_errors do
 resp = Stripe::Customer.create(
 description: 'Customer for DoctorNow',
 metadata: { customer_id: @customer.id },
 email: @customer.email,
 source: card
 )
 @customer.assign_attributes(
 stripe_customer_id: resp['id'],
 stripe_card_id: resp['sources']['data'][0]['id'],
 stripe_card_last4: resp['sources']['data'][0]['last4'],
 stripe_card_type: resp['sources']['data'][0]['brand']
 )
 event('card_preauth', 'customer_id', @customer.id)
 end 
 end
...
private
...
 def handle_errors
 begin
 yield
 rescue Stripe::CardError => e
 log_error('creating_card_card_error')
 rescue Stripe::InvalidRequestError => e
 log_error('create_card_invalid')
 rescue Stripe::AuthenticationError => e
 log_error('create_card_authentication')
 rescue Stripe::APIConnectionError => e
 log_error('create_card_connect')
 rescue Stripe::StripeError => e
 log_error('create_card_stripe')
 rescue => e
 log_error('create_card_generic')
 end
 end
answered Jul 29, 2015 at 16:42
\$\endgroup\$
3
\$\begingroup\$

Personally, I wouldn't want to see this in a model either (at least not an ActiveRecord model).

I'd probably go with something more like this:

app/controllers/customers_controller.rb

def create
 create_customer = CreateCustomer.new(params)
 create_customer.perform
 if create_customer.success?
 redirect_to some_path, notice: 'success'
 else
 render :err_show, status: :payment_required, json: create_customer.err
 end
end

app/interactors/create_customer.rb

class CreateCustomer
 attr_reader :customer, :card, :err
 def initialize(customer, parms)
 @customer = customer
 @card = {
 'object' => 'card', 'number' => card_number, 'exp_month' => card_expire_month, 'exp_year' => card_expire_year,
 'cvc' => card_cvc, 'address_zip' => parms['zipcode'], 'name' => "#{parms['first_name']} #{parms['last_name']}",
 'address_line1' => parms['street_address_1'], 'address_state' => parms['state'],
 'address_line2' => parms['street_address_2'], 'address_city' => parms['city']
 }
 @err = nil
 end
 def perform
 resp = Stripe::Customer.create(
 description: 'Customer for DoctorNow',
 metadata: { customer_id: @customer.id },
 email: @customer.email,
 source: card)
 @customer.assign_attributes(
 stripe_customer_id: resp['id'],
 stripe_card_id: resp['sources']['data'][0]['id'],
 stripe_card_last4: resp['sources']['data'][0]['last4'],
 stripe_card_type: resp['sources']['data'][0]['brand']
 )
 event('card_preauth', 'customer_id', @customer.id)
 rescue Stripe::CardError => e
 log_error('creating_card_card_error')
 rescue Stripe::InvalidRequestError => e
 log_error('create_card_invalid')
 rescue Stripe::AuthenticationError => e
 log_error('create_card_authentication')
 rescue Stripe::APIConnectionError => e
 log_error('create_card_connect')
 rescue Stripe::StripeError => e
 log_error('create_card_stripe')
 rescue => e
 log_error('create_card_generic')
 end
 def success?
 @err.nil? && @customer.stripe_customer_id.present?
 end
 private
 def log_error(error)
 @err = stripe_error(e, error, 0)
 event('card_preauth_failed', 'customer_id', @customer.id)
 end
end
answered Jul 23, 2015 at 18:17
\$\endgroup\$
1
  • \$\begingroup\$ I will give it a try. \$\endgroup\$ Commented Jul 23, 2015 at 19:09

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.