title: Ruby - code in else block executes even though Stripe exception WAS thrown
body: <p>Simplified version of my code:</p>
  
  <pre><code>1.upto(2) do |try|
    begin
      puts "Start"
    rescue =&gt; e
      if try == 2
        puts "Error - #{e}"
      end
    else
      puts "Success"
    end
  end
  </code></pre>
  
  <p>My problem is that when I have an error, this is what happens:</p>
  
  <pre><code>Start
  Start
  Error - some message
  Success
  </code></pre>
  
  <p>Really scratching my head here, because this is not what's supposed to happen... Any thoughts?</p>
  
  <h3>Update</h3>
  
  <p>OK I think I did myself a disservice by putting in the simplified version of the code, because that works, but the full version below, does not. I.e., when Stripe throws an API exception, the email is still triggering.</p>
  
  <pre><code>1.upto(2) do |try|
    Stripe.api_key = ENV['Stripe_Secret_Key']
    begin
      customer = Stripe::Customer.create(
        :source =&gt; params[:stripeToken],
        :email =&gt; @rentalrequest.email
      )
      @charge = Stripe::Charge.create(
        amount: (@rentalrequest.actual_amount * 100), # Stripe requires cents
        currency: "usd",
        customer: customer.id,
        description: "Payment from #{@rentalrequest.email} for gear rental"
      )
    rescue =&gt; e
      if try == 2
        logger.fatal "Stripe error: #{e.class}, #{e.message}"
        StripeErrorEmail.new.async.perform(e.class, e.message, @rentalrequest.id)
        render "rental_requests/new" and return
      end
    else
      RoadrunnerEmailAlert.new.async.perform(@rentalrequest.id)
    end
  end
  </code></pre>
  
  <p>In other words, both <code>StripeErrorEmail</code> and <code>RoadrunnerEmailAlert</code> are firing</p>
  
  <p><strong>UPDATE for KM's answer</strong></p>
  
  <pre><code>def error_handle(e, id)
    # Since it's a decline, Stripe::CardError will be caught
    body = e.json_body
    err  = body[:error]
  
    puts "Status is: #{e.http_status}"
    # =&gt; 400
    puts "Type is: #{err[:type]}"
    # =&gt; invalid_request_error
    puts "Code is: #{err[:code]}"
    # =&gt; nil
    puts "Param is: #{err[:param]}"
    # =&gt; nil
    puts "Message is: #{err[:message]}"
    # =&gt; You cannot use a Stripe token more than once
  
    logger.fatal "Stripe error: #{e.class}, #{e.message}"
    StripeErrorEmail.new.async.perform(e.class, e.message, id)
    render "rental_requests/new" and return
  end
  
  def charge
    @rentalrequest = RentalRequest.find(params[:rentalrequest_id])
  
    # Up to two tries
    1.upto(2) do |try|
      Stripe.api_key = ENV['Stripe_Secret_Key']
      begin
        customer = Stripe::Customer.create(
          :source =&gt; params[:stripeToken],
          :email =&gt; @rentalrequest.email
        )
        @charge = Stripe::Charge.create(
          amount: (@rentalrequest.actual_amount * 100), # Stripe requires cents
          currency: "usd",
          customer: customer.id,
          description: "Payment from #{@rentalrequest.email} for gear rental"
        )
      rescue Stripe::CardError =&gt; e
        if try == 2
          error_handle(e, @rentalrequest.id)
        end
      rescue Stripe::InvalidRequestError =&gt; e
        if try == 2
          error_handle(e, @rentalrequest.id)
        end
      rescue Stripe::AuthenticationError =&gt; e
        if try == 2
          error_handle(e, @rentalrequest.id)
        end
      rescue Stripe::APIConnectionError =&gt; e
        if try == 2
          error_handle(e, @rentalrequest.id)
        end
      rescue Stripe::StripeError =&gt; e
        if try == 2
          error_handle(e, @rentalrequest.id)
        end
      rescue =&gt; e
        if try == 2
          error_handle(e, @rentalrequest.id)
        end  
      else
        RoadrunnerEmailAlert.new.async.perform
      end
    end
  end
  </code></pre>