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
2 Answers 2
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
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
-
\$\begingroup\$ I will give it a try. \$\endgroup\$Antarr Byrd– Antarr Byrd2015年07月23日 19:09:40 +00:00Commented Jul 23, 2015 at 19:09
Explore related questions
See similar questions with these tags.
Stripe::*Error
's be thrown from? Inside@customer.assign_attributes(...)
or fromevent(...)
? \$\endgroup\$Stripe::Customer.create
\$\endgroup\$