Rails controller method to create a customer with credit card info 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' =&gt; 'card', 'number' =&gt; card_number, 'exp_month' =&gt; card_expire_month, 'exp_year' =&gt; card_expire_year,
        'cvc' =&gt; card_cvc, 'address_zip' =&gt; parms['zipcode'], 'name' =&gt; "#{parms['first_name']} #{parms['last_name']}",
        'address_line1' =&gt; parms['street_address_1'], 'address_state' =&gt; parms['state'],
        'address_line2' =&gt; parms['street_address_2'], 'address_city' =&gt; 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 =&gt; 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 =&gt; 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 =&gt; 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 =&gt; 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 =&gt; 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 =&gt; 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
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' =&gt; 'card', 'number' =&gt; card_number, 'exp_month' =&gt; card_expire_month, 'exp_year' =&gt; card_expire_year,
    'cvc' =&gt; card_cvc, 'address_zip' =&gt; parms['zipcode'], 'name' =&gt; "#{parms['first_name']} #{parms['last_name']}",
    'address_line1' =&gt; parms['street_address_1'], 'address_state' =&gt; parms['state'],
    'address_line2' =&gt; parms['street_address_2'], 'address_city' =&gt; 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 =&gt; e
    log_error('creating_card_card_error')
  rescue Stripe::InvalidRequestError =&gt; e
    log_error('create_card_invalid')
  rescue Stripe::AuthenticationError =&gt; e
    log_error('create_card_authentication')
  rescue Stripe::APIConnectionError =&gt; e
    log_error('create_card_connect')
  rescue Stripe::StripeError =&gt; e
    log_error('create_card_stripe')
  rescue =&gt; e
    log_error('create_card_generic')
  end

  def success?
    @err.nil? &amp;&amp; @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