Skip to content

Instantly share code, notes, and snippets.

@tmcdb
Last active February 21, 2017 21:32
Show Gist options
  • Save tmcdb/1e3891c83969e197f00b to your computer and use it in GitHub Desktop.
Save tmcdb/1e3891c83969e197f00b to your computer and use it in GitHub Desktop.

Revisions

  1. tmcdb revised this gist Nov 4, 2014. 1 changed file with 32 additions and 26 deletions.
    58 changes: 32 additions & 26 deletions integrating-rails-with-stripe-concise.md
    Original file line number Diff line number Diff line change
    @@ -519,12 +519,16 @@ def create
    end
    end
    ```
    2. Handle errors logging and notifying users.
    If you try making a purchase again you should be redirected to the receipt page where you'll see evidence of the purchase. Log in to your dashboard at Stripe and check that the test payment was successful https://dashboard.stripe.com/test/dashboard.

    ---
    ###Try making a purchase again
    Find evidence of the purchase upon redirection.

    ![Submitting test card details](https://raw.githubusercontent.com/tmcdb/stripe-tutorial-images/master/test-card.png)

    ###Check that the test payment was successful
    Log in to [Stripe Dashboard](https://dashboard.stripe.com/test/dashboard).

    Now that we're taking payments successfully for products – albeit rather boring and somewhat anonymous products – let's take care of payment failures.
    ---

    ###Error handling

    @@ -533,11 +537,10 @@ https://stripe.com/docs/testing#cards

    ![Card Declined](https://raw.githubusercontent.com/tmcdb/stripe-tutorial-images/master/declined-card.png)

    A `Stripe::CardError` exception will be raised. Let's take a look at Stripe's API documentation again to see how they suggest we handle errors:

    https://stripe.com/docs/api#errors
    A `Stripe::CardError` exception will be raised.

    We can rescue errors from our model and do something useful with them:
    ###Rescue Errors
    Do something useful with them https://stripe.com/docs/api#errors

    ```ruby
    # app/controllers/orders_controller.rb
    @@ -570,9 +573,15 @@ rescue Stripe::CardError => e
    end
    ```

    The code between rescue and end only executes if the app tries to raise the named exception. So if we type in the details again and the card is declined the error message will be passed to the flash hash and the form will be rendered again.
    The code between rescue and end only executes if the app tries to raise the named exception.

    ###Submit the details again

    ![Card Declined](https://raw.githubusercontent.com/tmcdb/stripe-tutorial-images/master/declined-card.png)

    The card is declined the error message will be passed to the flash hash and the form will be rendered again.

    Let's display the flash messages in the browser with some code in the application layout view:
    ###Display the flash messages

    ```HTML+ERB
    # app/views/layouts/application.html.erb
    @@ -592,12 +601,14 @@ Let's display the flash messages in the browser with some code in the applicatio
    </html>
    ```

    Now if we submit the `4000 0000 0000 0002` card details, we'll be redirected to the form along with an error message.
    ###Submit the `4000 0000 0000 0002` card details yet again
    And be redirected to the form along with an error message.


    ### Heroku Deployment

    Once you've downloaded the [Herkou toolbelt](http://toolbelt.heroku.com) it's dead easy to Deploy to heroku. The toolbelt gives you a suite of commands to issue on the command line.
    ###Download the [Herkou toolbelt](http://toolbelt.heroku.com)
    Deploy to heroku.

    ```bash
    $ heroku login
    @@ -623,13 +634,9 @@ Git remote heroku added
    ```bash
    $ heroku open
    ```

    ![$ heroku open](https://raw.githubusercontent.com/tmcdb/stripe-tutorial-images/master/heroku-open.png)

    ### Settings

    There are some Gems we need for deploying to Heroku with Rails 4.

    ###Setup Gems for deployment
    ```ruby
    group :development, :test do
    gem 'sqlite3'
    @@ -645,11 +652,9 @@ ruby '2.1.2'
    ```bash
    $ bundle install
    ```

    The `rails_12factor` Gem handles some configuration necessary for running a Rails app on Heroku. The `pg` Gem is the Ruby interface to PostgreSQL, which is the database required for a Rails app running on Heroku, so wrap `gem 'sqlite3'` in a block specefying development and test environments and use `gem 'pg'` in your production enviroment.

    > For info on dev/prod parity see [here](https://gist.github.com/tmcdb/6aa96a88d7e2355a6b2b).

    ###Commit and deploy
    ```bash
    $ git add -A .
    $ git commit -m 'heroku config'
    @@ -668,11 +673,12 @@ To [email protected]:tmcdb/paymental.git
    $ git push heroku master
    ```

    Reload your app in the browser and notice the error page.
    ###Reload the browser
    Notice the error.

    ![Heroku Error](https://raw.githubusercontent.com/tmcdb/stripe-tutorial-images/master/heroku-error.png)

    We can't see the cause of the error in the browser but we can debug it at the command line.
    ###Debug the error at the command-line.

    ```bash
    $ heroku logs
    @@ -683,9 +689,8 @@ $ heroku logs
    ...
    ```

    The exception is a `PG::UndefinedTable` exception. This tells me that I need to rake the database on the server.

    Heroku lets us connect to the server and run commands just as we would locally with `herkou run`.
    The exception is a `PG::UndefinedTable` exception.
    ###Rake the database on the server.

    ```bash
    $ heroku run rake db:migrate
    @@ -706,7 +711,8 @@ Migrating to CreateOrders (20141015131508)

    ```
    Reloading the browser now should give us access to the live app!
    ###Reload the browser
    See the live app!
    ### Stripe Live Keys
  2. tmcdb revised this gist Nov 4, 2014. 1 changed file with 18 additions and 48 deletions.
    66 changes: 18 additions & 48 deletions integrating-rails-with-stripe-concise.md
    Original file line number Diff line number Diff line change
    @@ -365,6 +365,7 @@ Make sure the number in this URL http://0.0.0.0:3000/products/1/orders/new corre
    ###Retrieve a `stripe_token` to submit with form.
    Use the form element's correct `id` attribute value (`form_for` method in the view code automatically provides `id="new_order"`).

    ```js
    # app/views/layoutes/application.html.erb
    @@ -385,13 +386,9 @@ jQuery(function($) {
    ```

    Make sure to change the jQuery selector that grabs the form to include your form element's correct `id` attribute value. The `form_for` method in the view code automatically provides our form tag with `id="new_order"`.
    ###Save the response object's `id`
    Handle the Stripe response and append an input element with a `name` attribute to the form before submitting.

    The `createToken` function packages the credit card info into a single-use token that is subsequently sent to Stripe for validation. We get a response object back from Stripe, and want to save the `id` of this object to our DB for use later when creating a charge for our product when we save an order.

    To save the response object's `id` we use Stripe.js to append an input element with a `name` attribute to our form before submitting it to our server.

    Below we can define the function that handles the response and is passed as a second argument to `createToken` above.
    ```js
    function stripeResponseHandler(status, response) {
    var $form = $('#new_order'); // change the selector that gets the form to #new_order
    @@ -411,37 +408,24 @@ function stripeResponseHandler(status, response) {
    }
    ```

    Again, change the jQuery selector from the example given in Stripe's docs. We'll also need to make sure the newly appended input field's `name` attribute is appropriate for intercepting the data with Rails in the traditional way:
    ###Permit the stripe\_token param
    It comes from the `<input name='order[stripe_token]' >` element appended by the code above.

    ```ruby
    # app/controllers/orders_controller.rb
    private
    def order_params
    params.require(:order).permit(:stripe_token)
    end
    # The syntax above will only find and permit the "stripe_token" attribute if it's nested inside "order".
    # params = {
    # "utf8" => "✓",
    # "authenticity_token" => "sSlwx4lcH8pQYHrT9C5RR50sgbsazaCw16SegVsoiaA=",
    # "order" => {
    # "stripe_token"=>"tok_14pfah2uVktQRyY5UIs2cIhP"
    # },
    # "action" => "create",
    # "controller" => "orders",
    # "product_id" => "1"
    # }
    # To achieve that we appended "<input name="order[stripe_token]" />" to our form using jQuery.
    ```

    At this point we're able to verify via Stripe whether someone has a valid form of payment. We can submit test card data and see whether or no we're saving the `stripe_token`'s `id` in our DB.
    ###Submit test card data
    See whether or not the `stripe_token`'s `id` is saved to the DB.

    ![Submitting test card details](https://raw.githubusercontent.com/tmcdb/stripe-tutorial-images/master/test-card.png)

    To see whether or not the data was saved, define a `show` action in your orders controller like so:

    ###Define a `show` action in the orders controller

    ```ruby
    # app/controller/orders.rb
    @@ -451,7 +435,7 @@ def show
    end
    ```

    ...and create a receipt page:
    ###Create a receipt page:

    ```HTML+ERB
    # app/views/orders/show.html.erb
    @@ -463,33 +447,23 @@ end
    </article>
    ```

    The next step is to use Stripe's Ruby API to create a charge using `@order.stripe_token` – a reference to the verified card details recognisable to Stripe.

    ---


    ### Creating a charge
    #Stripe's Ruby API
    ## Create a charge
    Read through Stripe's Full Api reference before continuing https://stripe.com/docs/api#charges.

    It's a good idea to have a read through Stripe's Full Api reference before continuing.

    At the very least we need to use to Stripe's API to create a charge object and, in so doing, take payment for a product on our site. Let's have a look at Stripe's charge object and find out how to create one.

    https://stripe.com/docs/api#charges

    The object is quite large but thankfully to create one we only need to bundle the Stripe gem, call the `createCharge` method and pass a few required arguments.

    https://stripe.com/docs/api#create_charge
    ###Bundle the Stripe Gem

    ```ruby
    # Gemfile
    gem 'stripe', :git => 'https://github.com/stripe/stripe-ruby'
    ```

    ```bash
    $ bundle install
    ```
    ###Call the `createCharge` method
    https://stripe.com/docs/api#create_charge

    ```ruby
    # app/controllers/orders_controller.rb
    @@ -518,11 +492,7 @@ end

    Stripe will return a charge object if the charge succeeds, it will raise an error if it fails.

    If you try to buy something you'll see an error complaining that Stripe's API key is not set and there are two things we want to do.
    1. Set the API key to silence the complaint.
    2. Handle errors logging and notifying users.

    First reference the secret key from `config/secrets.yml` in the controller.
    ###Set the API key to silence the complaint.

    ```ruby
    # app/controllers/orders_controller.rb
    @@ -549,7 +519,7 @@ def create
    end
    end
    ```

    2. Handle errors logging and notifying users.
    If you try making a purchase again you should be redirected to the receipt page where you'll see evidence of the purchase. Log in to your dashboard at Stripe and check that the test payment was successful https://dashboard.stripe.com/test/dashboard.

    ---
  3. tmcdb revised this gist Nov 4, 2014. 1 changed file with 38 additions and 30 deletions.
    68 changes: 38 additions & 30 deletions integrating-rails-with-stripe-concise.md
    Original file line number Diff line number Diff line change
    @@ -148,7 +148,8 @@ end

    ```

    Use the rails path helpers to link to the `orders/new.html.erb` page.
    ###Link to the `orders/new.html.erb` page.
    Use `no_turbolink: true` option so the page _actually_ loads after clicking (in stead of using turbolinks).
    ```HTML+ERB
    # app/views/products/index.html.erb
    # ...
    @@ -167,9 +168,13 @@ Use the rails path helpers to link to the `orders/new.html.erb` page.
    ```

    The `no_turbolink: true` option means the page _actually_ loads after clicking the "Buy" link in stead of using turbolinks. For more on turbolinks [see here](https://gist.github.com/tmcdb/590476e0049c343476b3).
    [More on turbolinks](https://gist.github.com/tmcdb/590476e0049c343476b3).

    Clicking this link in the browser will cause our app to try and route us to a controller that doesn't yet exist. We will see an `UninitializedConstant` Exception. Let's generate the controller now, along with `new` and `create` actions and a form at `app/views/orders/new.html.erb`
    ###Try the link
    And see an `UninitializedConstant` Exception.

    ###Generate the controller
    With `new` and `create` actions and a form at `app/views/orders/new.html.erb`.

    ```bash
    $ rails g controller Orders new
    @@ -204,7 +209,13 @@ end

    ```

    If we try to click through to the new order page now we'll see a `NoMethodError`. The line with the complaint is trying to reference an `Order` model. Let's generate that model now and set up the association between a `Product` and an `Order`.
    ###Try the link again
    And see a `NoMethodError`.



    ###Generate `Order` model


    ```bash
    $ rails g model Order stripe_token product_id:integer
    @@ -216,19 +227,16 @@ $ rake db:migrate
    -> 0.0038s
    == 20141024181050 CreateOrders: migrated (0.0039s) ============================
    ```

    Defining the association below will make a `product` method available on `Order` instances.

    ###Associate models with eachother
    Make a `product` method available to [_call_](https://gist.github.com/tmcdb/62f616303b09918dcfcf) on `Order` instances:
    ```ruby
    # app/models/order.rb
    class Order > ActiveRecord::Base
    belongs_to :product
    end
    ```

    Likewise defining this association below will make an `orders` method available to [_call_](https://gist.github.com/tmcdb/62f616303b09918dcfcf) on `Product` instances.


    Make an `orders` method available to [call](https://gist.github.com/tmcdb/62f616303b09918dcfcf) on `Product` instances.
    ```ruby
    # app/models/product.rb
    class Product > ActiveRecord::Base
    @@ -237,13 +245,11 @@ end

    ```

    Now when we click the link, we'll be routed through to the new view (in stead of seeing a `NoMethodError`), which currently contains nothing more than markup explaining where to find the file.
    ###Try the link a third time
    Find nothing more than markup explaining where to find the file (not a `NoMethodError` as before).

    ### Custom Stripe Form

    Next we need to replace the markup at `app/views/orders/new.html.erb` with a Stripe form. Stripe's documentation provides a thorough description of the process of accessing their API via ajax through a custom form.

    I'll use the `form_for` method to build the form tag.
    ## Custom Stripe Form
    ###Replace the markup at `app/views/orders/new.html.erb` with `form_for` method.
    ```HTML+ERB
    <%= form_for [@product, @order] do |f| %>
    @@ -253,8 +259,7 @@ I'll use the `form_for` method to build the form tag.
    ```

    We're going to copy the markup from Stripe's documentation: [https://stripe.com/docs/tutorials/forms](https://stripe.com/docs/tutorials/forms).

    ###Copy the markup from Stripe's documentation [https://stripe.com/docs/tutorials/forms](https://stripe.com/docs/tutorials/forms).

    ```HTML+ERB
    <%= form_for [@product, @order] do |f| %>
    @@ -288,13 +293,11 @@ We're going to copy the markup from Stripe's documentation: [https://stripe.com/
    ```

    Notice that the none of the input elements that I've copied into the block above have `name` attributes.

    The name attribute of an input element is how we name the data being submitted through the form. We can use the name to collect the data on the server side. By omitting the name attributes from this form we can be sure that our servers never see the card credentials of our customers.

    ### Stripe.js
    >Note that the none of the input elements that I've copied into the block above have `name` attributes.The name attribute of an input element is how we name the data being submitted through the form. We can use the name to collect the data on the server side. By omitting the name attributes from this form we can be sure that our servers never see the card credentials of our customers.
    Stripe's javascript code in Stripe.js enables us to communicate with Stripe. We need to include it to reference their functions, which we'll be using to _send_ and _recieve_ data _to_ and _from_ their servers.
    ## Stripe.js
    ###Include Stripe.js
    For communicating with Stripe's servers.

    ```HTML+ERB
    # app/views/layouts/application.html.erb
    @@ -314,9 +317,8 @@ Stripe's javascript code in Stripe.js enables us to communicate with Stripe. We
    ```

    I've included this directly between the `<head></head>` tags as per Stripe's recommendation but I've included an `if` statement to ensure Stripe's servers are only contacted on the appropriate pages.

    Open a new script tag underneath to paste in Stripe's boilerplate JS code which will send the credit card details to Stripe for authentication.
    ###Set publishable key
    For identifying your site with Stripe.

    ```HTML+ERB
    # app/views/layouts/application.html.erb
    @@ -341,7 +343,8 @@ Open a new script tag underneath to paste in Stripe's boilerplate JS code which
    ```

    This `setPublishableKey` function identifies your site when communicating with Stripe. I've replaced the key (which is available from your Stripe Dashboard upon [logging in](https://dashboard.stripe.com/account/apikeys)) with a reference to a configuration variable `Rails.application.secrets.stripe_public_key`, that I will set in `config/secrets.yml`:
    ###Save secret and public keys
    From [Stripe Dashboard](https://dashboard.stripe.com/account/apikeys) copy them to `config/secrets.yml`.

    ```yml
    # config/secrets.yml
    @@ -353,10 +356,15 @@ development:
    > Setting the test keys in plain text in this file isn't a security risk because charges can't be made via Stripe using these keys. However if you're hosting the code on [Github](http://github.com) or [Bitbucket](http://bitbucket.com) publicly you may still want to hide the test keys in case someone ends up using them accidently, which might be confusing for you. The _live_ secret key by contrast must *always* remain hidden from public view under shell variables.
    To check that view code is getting the correct key from the secrets file, restart your server and point your browser to http://0.0.0.0:3000/products/1/orders/new (make sure the number in the URL corresponds to a valid product_id) and open up the web inspector to and look for the publishable key in the inline JS code.
    ###Restart the server and point check browser
    Make sure the number in this URL http://0.0.0.0:3000/products/1/orders/new corresponds to a valid product_id
    ###Use web inspector to verify the publishable key
    ![Stripe Publishable Key](https://raw.githubusercontent.com/tmcdb/stripe-tutorial-images/master/stripe_publishable_key.png)
    Once you've confirmed that the publishable key is available in the browser (`pk_test_<HASH>`) we can continue following the Stripe Docs and add the JS code that will send the card details to Stripe and retrieve a `stripe_token` to submit with our form.
    ###Retrieve a `stripe_token` to submit with form.

    ```js
    # app/views/layoutes/application.html.erb
  4. tmcdb revised this gist Nov 4, 2014. 1 changed file with 15 additions and 12 deletions.
    27 changes: 15 additions & 12 deletions integrating-rails-with-stripe-concise.md
    Original file line number Diff line number Diff line change
    @@ -36,29 +36,30 @@ If you don't have any of the above follow [this tutorial](https://gist.github.co

    ### New project

    I'll be using the scaffold generator to save time. It generates a Model, a Migration, a Controller and Views – all replete with boilerplate code.

    ```bash
    $ rails new paymental
    $ cd paymental
    ```
    Immediately initialize your project as a Git repo, so you can track every change made to the codebase.
    ### Immediately initialize your project as a Git repo
    So you can track every change made to the codebase.

    ```bash
    $ git init
    $ git add .
    $ git commit -m 'initial commit'
    ```

    Push it to your prefered code host for collaboration and backup purposes.
    ###Push it to your prefered code host
    For collaboration and backup purposes.

    ```bash
    $ git remote add origin git [email protected]:tmcdb/paymental.git
    $ git push -u origin master

    ```

    At this point it's normally a good idea to run the app and point your browser at the empty project's landing page.
    ###Run the app
    Point your browser at the empty project's landing page.

    ```bash
    $ rails s
    @@ -72,7 +73,8 @@ $ rails s
    ```

    I like to open a new shell and keep the server running in the background.
    ###Open a new shell
    To keep the server running in the background.

    >Remember to restart the server whenever you make a change that needs initialising – new Gems, config settings etc.
    @@ -81,7 +83,7 @@ I like to open a new shell and keep the server running in the background.
    $ cd ~/Sites/rails_projects/paymental
    ```

    From here I can begin coding proper.
    ##Code

    We need a model for Products we're selling:

    @@ -97,9 +99,8 @@ The scaffold generator takes the same arguments as the Model generator:

    ### Raking the DB

    At this point it's always a good idea to investigate the code that was generated by the generator.
    Check the code that was generated by the generator.

    Take a look at the migration file:
    ```ruby
    # db/migrate/20141015105111_create_products.rb
    class CreateProducts < ActiveRecord::Migration
    @@ -114,8 +115,8 @@ class CreateProducts < ActiveRecord::Migration
    end
    end
    ```

    After confirming the contents of the migration file are correct, rake the DB.
    ###Rake the DB.
    After confirming the contents of the migration file are correct.

    ```bash
    $ rake db:migrate
    @@ -127,7 +128,9 @@ $ rake db:migrate
    == 20141015105111 CreateProducts: migrated (0.0014s) ==========================
    ```

    Pointing the browser to http://0.0.0.0:3000/products will show us an empty table of products and a link to create a new one. Go ahead and add in some products ready for us to purchase through Stripe.
    ###Check the browser

    Add in some products ready purchasing through Stripe http://0.0.0.0:3000/products.

    ### Generating Orders

  5. tmcdb revised this gist Nov 4, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion integrating-rails-with-stripe-concise.md
    Original file line number Diff line number Diff line change
    @@ -77,7 +77,7 @@ I like to open a new shell and keep the server running in the background.
    >Remember to restart the server whenever you make a change that needs initialising – new Gems, config settings etc.
    ```bash
    # Open a new Terminal window, ⌘ + n
    # Open a new Terminal window, + n
    $ cd ~/Sites/rails_projects/paymental
    ```

  6. tmcdb revised this gist Nov 4, 2014. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion integrating-rails-with-stripe-concise.md
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    # Integrating Stripe with Rails
    # Integrating Stripe with Rails (Concise)

    This written tutorial is a concise version of [this tutorial](https://gist.github.com/tmcdb/a989e2f7a6a04dbef279), which covers building a payment system into a Rails app using [Stripe.js](https://stripe.com/gb). It assumes a basic familiarity with [Ruby on Rails](http://rubyonrails.org/), [Git](http://git-scm.com/) and the [command-line](https://gist.github.com/tmcdb/62f616303b09918dcfcf).

  7. tmcdb created this gist Nov 4, 2014.
    757 changes: 757 additions & 0 deletions integrating-rails-with-stripe-concise.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,757 @@
    # Integrating Stripe with Rails

    This written tutorial is a concise version of [this tutorial](https://gist.github.com/tmcdb/a989e2f7a6a04dbef279), which covers building a payment system into a Rails app using [Stripe.js](https://stripe.com/gb). It assumes a basic familiarity with [Ruby on Rails](http://rubyonrails.org/), [Git](http://git-scm.com/) and the [command-line](https://gist.github.com/tmcdb/62f616303b09918dcfcf).

    ### What's covered

    - Setting up a basic Rails app with a scaffold generator
    - Integrating Stripe charges
    - Deploying to Heroku

    ### What you'll need

    - Ruby 1.9.3 or higher – http://rvm.io/
    - Rails 4 – http://rubyonrails.org/
    - Postgresql – http://brew.sh/
    - Heroku toolbelt – http://toolbelt.heroku.com/
    - Git - http://git-scm.com/
    - An IDE – http://www.sublimetext.com/

    ### Don't have what you need?

    If you don't have any of the above follow [this tutorial](https://gist.github.com/tmcdb/d9173ddac43f8bea8882) on setting up your environment for Ruby on Rails with Heroku. If you're unfamiliar with command-line basics [this tutorial](https://gist.github.com/tmcdb/62f616303b09918dcfcf) on the command-line for beginners will be helpful.

    ### Contents

    - [New Project](#new-project)
    - [Raking the DB](#raking-the-db)
    - [Generating Orders](#generating-orders)
    - [Custom Stripe Form](#custom-stripe-form)
    - [Stripe.js](#stripejs)
    - [Error Handling](#error-handling)
    - [Deployment to Heroku](#heroku-deployment)
    - [Stripe Live Keys](#stripe-live-keys)

    ---

    ### New project

    I'll be using the scaffold generator to save time. It generates a Model, a Migration, a Controller and Views – all replete with boilerplate code.

    ```bash
    $ rails new paymental
    $ cd paymental
    ```
    Immediately initialize your project as a Git repo, so you can track every change made to the codebase.

    ```bash
    $ git init
    $ git add .
    $ git commit -m 'initial commit'
    ```

    Push it to your prefered code host for collaboration and backup purposes.

    ```bash
    $ git remote add origin git [email protected]:tmcdb/paymental.git
    $ git push -u origin master

    ```

    At this point it's normally a good idea to run the app and point your browser at the empty project's landing page.

    ```bash
    $ rails s
    ```
    ```irb
    => Booting WEBrick
    => Rails 4.1.4 application starting in development on http://0.0.0.0:3000
    => Run `rails server -h` for more startup options
    => Ctrl-C to shutdown server
    ...etc...
    ```

    I like to open a new shell and keep the server running in the background.

    >Remember to restart the server whenever you make a change that needs initialising – new Gems, config settings etc.
    ```bash
    # Open a new Terminal window, ⌘ + n
    $ cd ~/Sites/rails_projects/paymental
    ```

    From here I can begin coding proper.

    We need a model for Products we're selling:

    ```bash
    $ rails g scaffold Product name color price_in_pence:integer
    ```

    The scaffold generator takes the same arguments as the Model generator:

    - Model name, (singular version of the resource)
    - Attribute names (columns in the table)
    - Data types (e.g. string, integer, boolean etc.)

    ### Raking the DB

    At this point it's always a good idea to investigate the code that was generated by the generator.

    Take a look at the migration file:
    ```ruby
    # db/migrate/20141015105111_create_products.rb
    class CreateProducts < ActiveRecord::Migration
    def change
    create_table :products do |t|
    t.string :name
    t.string :color
    t.integer :price_in_pence

    t.timestamps
    end
    end
    end
    ```

    After confirming the contents of the migration file are correct, rake the DB.

    ```bash
    $ rake db:migrate
    ```
    ```irb
    == 20141015105111 CreateProducts: migrating ===================================
    -- create_table(:products)
    -> 0.0013s
    == 20141015105111 CreateProducts: migrated (0.0014s) ==========================
    ```

    Pointing the browser to http://0.0.0.0:3000/products will show us an empty table of products and a link to create a new one. Go ahead and add in some products ready for us to purchase through Stripe.

    ### Generating Orders

    To place an order I'll need a model called `Order`, a controller and some views, and routes (URLs).

    #####Routes:
    ```ruby
    # config/routes.rb
    Rails.application.routes.draw do
    root 'products#index'
    resources :products do
    resources :orders
    end
    end

    ```

    Use the rails path helpers to link to the `orders/new.html.erb` page.
    ```HTML+ERB
    # app/views/products/index.html.erb
    # ...
    <% @products.each do |product" %>
    # ...
    <%= link_to "Buy", new_product_order_path(product), data: { no_turbolink: true } %>
    # ...
    <% end %>
    # ...
    ```

    The `no_turbolink: true` option means the page _actually_ loads after clicking the "Buy" link in stead of using turbolinks. For more on turbolinks [see here](https://gist.github.com/tmcdb/590476e0049c343476b3).

    Clicking this link in the browser will cause our app to try and route us to a controller that doesn't yet exist. We will see an `UninitializedConstant` Exception. Let's generate the controller now, along with `new` and `create` actions and a form at `app/views/orders/new.html.erb`

    ```bash
    $ rails g controller Orders new

    ```

    ```ruby
    # app/controllers/orders_controller.rb
    class OrdersController < ApplicationController
    def new
    @product = Product.find(params[:product_id])
    @order = @product.orders.new
    end

    def create
    @product = Product.find(params[:product_id])
    @order = @product.orders.new(order_params)
    if @order.save
    flash[:success] = "Thanks for purchasing #{@product.name}"
    redirect_to product_order_path(@product, @order)
    else
    flash[:error] = "Oops, something went wrong"
    render :new
    end
    end

    private
    def order_params
    params.require(:order).permit(:product_id, :stripe_token)
    end
    end

    ```

    If we try to click through to the new order page now we'll see a `NoMethodError`. The line with the complaint is trying to reference an `Order` model. Let's generate that model now and set up the association between a `Product` and an `Order`.

    ```bash
    $ rails g model Order stripe_token product_id:integer
    $ rake db:migrate
    ```
    ```irb
    == 20141024181050 CreateOrders: migrating =====================================
    -- create_table(:orders)
    -> 0.0038s
    == 20141024181050 CreateOrders: migrated (0.0039s) ============================
    ```

    Defining the association below will make a `product` method available on `Order` instances.

    ```ruby
    # app/models/order.rb
    class Order > ActiveRecord::Base
    belongs_to :product
    end
    ```

    Likewise defining this association below will make an `orders` method available to [_call_](https://gist.github.com/tmcdb/62f616303b09918dcfcf) on `Product` instances.


    ```ruby
    # app/models/product.rb
    class Product > ActiveRecord::Base
    has_many :orders
    end

    ```

    Now when we click the link, we'll be routed through to the new view (in stead of seeing a `NoMethodError`), which currently contains nothing more than markup explaining where to find the file.

    ### Custom Stripe Form

    Next we need to replace the markup at `app/views/orders/new.html.erb` with a Stripe form. Stripe's documentation provides a thorough description of the process of accessing their API via ajax through a custom form.

    I'll use the `form_for` method to build the form tag.
    ```HTML+ERB
    <%= form_for [@product, @order] do |f| %>
    # ...Stripe form goes here...
    <% end %>
    ```

    We're going to copy the markup from Stripe's documentation: [https://stripe.com/docs/tutorials/forms](https://stripe.com/docs/tutorials/forms).


    ```HTML+ERB
    <%= form_for [@product, @order] do |f| %>
    <span class="payment-errors"></span>
    <div class="form-row">
    <label>
    <span>Card Number</span>
    <input type="text" size="20" data-stripe="number"/>
    </label>
    </div>
    <div class="form-row">
    <label>
    <span>CVC</span>
    <input type="text" size="4" data-stripe="cvc"/>
    </label>
    </div>
    <div class="form-row">
    <label>
    <span>Expiration (MM/YYYY)</span>
    <input type="text" size="2" data-stripe="exp-month"/>
    </label>
    <span> / </span>
    <input type="text" size="4" data-stripe="exp-year"/>
    </div>
    <button type="submit">Submit Payment</button>
    <% end %>
    ```

    Notice that the none of the input elements that I've copied into the block above have `name` attributes.

    The name attribute of an input element is how we name the data being submitted through the form. We can use the name to collect the data on the server side. By omitting the name attributes from this form we can be sure that our servers never see the card credentials of our customers.

    ### Stripe.js

    Stripe's javascript code in Stripe.js enables us to communicate with Stripe. We need to include it to reference their functions, which we'll be using to _send_ and _recieve_ data _to_ and _from_ their servers.

    ```HTML+ERB
    # app/views/layouts/application.html.erb
    <!DOCTYPE html>
    <html>
    <head>
    <title>Paymental</title>
    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
    <%= csrf_meta_tags %>
    <% if params[:controller] == "orders" and params[:action] == "new" or params[:action] == "create" %>
    <script type="text/javascript" src="https://js.stripe.com/v2/"></script>
    <% end %>
    ```

    I've included this directly between the `<head></head>` tags as per Stripe's recommendation but I've included an `if` statement to ensure Stripe's servers are only contacted on the appropriate pages.

    Open a new script tag underneath to paste in Stripe's boilerplate JS code which will send the credit card details to Stripe for authentication.

    ```HTML+ERB
    # app/views/layouts/application.html.erb
    <!DOCTYPE html>
    <html>
    <head>
    <title>Paymental</title>
    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
    <%= csrf_meta_tags %>
    <% if params[:controller] == "orders" and params[:action] == "new" or params[:action] == "create" %>
    <script type="text/javascript" src="https://js.stripe.com/v2/"></script>
    <script type="text/javascript">
    // This identifies your website in the createToken call below
    Stripe.setPublishableKey('<%= Rails.application.secrets.stripe_public_key %>');
    // ...
    </script>
    <% end %>
    </head>
    ```

    This `setPublishableKey` function identifies your site when communicating with Stripe. I've replaced the key (which is available from your Stripe Dashboard upon [logging in](https://dashboard.stripe.com/account/apikeys)) with a reference to a configuration variable `Rails.application.secrets.stripe_public_key`, that I will set in `config/secrets.yml`:

    ```yml
    # config/secrets.yml
    development:
    secret_key_base: 1234571uyo2ehbdlwceiug86751836..etc...
    stripe_secret_key: sk_test_vdu32vdp23iy0894h...etc...
    stripe_public_key: pk_test_G124ij9wfmwoim03n...etc...
    ```
    > Setting the test keys in plain text in this file isn't a security risk because charges can't be made via Stripe using these keys. However if you're hosting the code on [Github](http://github.com) or [Bitbucket](http://bitbucket.com) publicly you may still want to hide the test keys in case someone ends up using them accidently, which might be confusing for you. The _live_ secret key by contrast must *always* remain hidden from public view under shell variables.
    To check that view code is getting the correct key from the secrets file, restart your server and point your browser to http://0.0.0.0:3000/products/1/orders/new (make sure the number in the URL corresponds to a valid product_id) and open up the web inspector to and look for the publishable key in the inline JS code.
    ![Stripe Publishable Key](https://raw.githubusercontent.com/tmcdb/stripe-tutorial-images/master/stripe_publishable_key.png)
    Once you've confirmed that the publishable key is available in the browser (`pk_test_<HASH>`) we can continue following the Stripe Docs and add the JS code that will send the card details to Stripe and retrieve a `stripe_token` to submit with our form.

    ```js
    # app/views/layoutes/application.html.erb
    jQuery(function($) {
    $('#new_order').submit(function(event) { // change $('#payment-form') to $('#new_order')
    var $form = $(this);
    // Disable the submit button to prevent repeated clicks
    $form.find('button').prop('disabled', true);
    Stripe.card.createToken($form, stripeResponseHandler);
    // Prevent the form from submitting with the default action
    return false;
    });
    });
    ```

    Make sure to change the jQuery selector that grabs the form to include your form element's correct `id` attribute value. The `form_for` method in the view code automatically provides our form tag with `id="new_order"`.

    The `createToken` function packages the credit card info into a single-use token that is subsequently sent to Stripe for validation. We get a response object back from Stripe, and want to save the `id` of this object to our DB for use later when creating a charge for our product when we save an order.

    To save the response object's `id` we use Stripe.js to append an input element with a `name` attribute to our form before submitting it to our server.

    Below we can define the function that handles the response and is passed as a second argument to `createToken` above.
    ```js
    function stripeResponseHandler(status, response) {
    var $form = $('#new_order'); // change the selector that gets the form to #new_order
    if (response.error) {
    // Show the errors on the form
    $form.find('.payment-errors').text(response.error.message);
    $form.find('button').prop('disabled', false);
    } else {
    // response contains id and card, which contains additional card details
    var token = response.id;
    // Insert the token into the form so it gets submitted to the server
    $form.append($('<input type="hidden" name="order[stripe_token]" />').val(token)); // Change the name attribute to correspond to rails' expected format for the params object.
    // and submit
    $form.get(0).submit();
    }
    }
    ```

    Again, change the jQuery selector from the example given in Stripe's docs. We'll also need to make sure the newly appended input field's `name` attribute is appropriate for intercepting the data with Rails in the traditional way:

    ```ruby
    # app/controllers/orders_controller.rb
    private
    def order_params
    params.require(:order).permit(:stripe_token)
    end
    # The syntax above will only find and permit the "stripe_token" attribute if it's nested inside "order".
    # params = {
    # "utf8" => "✓",
    # "authenticity_token" => "sSlwx4lcH8pQYHrT9C5RR50sgbsazaCw16SegVsoiaA=",
    # "order" => {
    # "stripe_token"=>"tok_14pfah2uVktQRyY5UIs2cIhP"
    # },
    # "action" => "create",
    # "controller" => "orders",
    # "product_id" => "1"
    # }
    # To achieve that we appended "<input name="order[stripe_token]" />" to our form using jQuery.
    ```

    At this point we're able to verify via Stripe whether someone has a valid form of payment. We can submit test card data and see whether or no we're saving the `stripe_token`'s `id` in our DB.

    ![Submitting test card details](https://raw.githubusercontent.com/tmcdb/stripe-tutorial-images/master/test-card.png)

    To see whether or not the data was saved, define a `show` action in your orders controller like so:

    ```ruby
    # app/controller/orders.rb
    def show
    @order = Order.find(params[:id])
    @price = @order.product.price_in_pence.to_f / 100
    end
    ```

    ...and create a receipt page:

    ```HTML+ERB
    # app/views/orders/show.html.erb
    <article>
    <h1>Thank you</h1>
    <h2><%= @order.product.name %></h2>
    <p>£ <%= @price %></p>
    <p>Stripe token: <%= @order.stripe_token %></p>
    </article>
    ```

    The next step is to use Stripe's Ruby API to create a charge using `@order.stripe_token` – a reference to the verified card details recognisable to Stripe.

    ---


    ### Creating a charge

    It's a good idea to have a read through Stripe's Full Api reference before continuing.

    At the very least we need to use to Stripe's API to create a charge object and, in so doing, take payment for a product on our site. Let's have a look at Stripe's charge object and find out how to create one.

    https://stripe.com/docs/api#charges

    The object is quite large but thankfully to create one we only need to bundle the Stripe gem, call the `createCharge` method and pass a few required arguments.

    https://stripe.com/docs/api#create_charge

    ```ruby
    # Gemfile
    gem 'stripe', :git => 'https://github.com/stripe/stripe-ruby'
    ```

    ```bash
    $ bundle install
    ```

    ```ruby
    # app/controllers/orders_controller.rb
    def create
    @product = Product.find(params[:product_id])
    @order = @product.orders.new(order_params)
    if @order.save
    Stripe::Charge.create(
    :amount => @product.price_in_pence,
    :currency => "gbp",
    :card => @order.stripe_token # obtained with Stripe.js
    )
    flash[:success] = "Thanks for purchasing #{@product.name}"
    redirect_to product_order_path(@product, @order)
    else
    flash[:error] = "Oops, something went wrong"
    render :new
    end
    ```

    Stripe will return a charge object if the charge succeeds, it will raise an error if it fails.

    If you try to buy something you'll see an error complaining that Stripe's API key is not set and there are two things we want to do.
    1. Set the API key to silence the complaint.
    2. Handle errors logging and notifying users.

    First reference the secret key from `config/secrets.yml` in the controller.

    ```ruby
    # app/controllers/orders_controller.rb
    def create
    @product = Product.find(params[:product_id])
    @order = @product.orders.new(order_params)
    if @order.save
    Stripe.api_key = Rails.application.secrets.stripe_secret_key # set the secret key to identify with stripe.
    Stripe::Charge.create(
    :amount => @product.price_in_pence,
    :currency => "gbp",
    :card => @order.stripe_token # obtained with Stripe.js
    )
    flash[:success] = "Thanks for purchasing #{@product.name}"
    redirect_to product_order_path(@product, @order)
    else
    flash[:error] = "Oops, something went wrong"
    render :new
    end
    end
    ```

    If you try making a purchase again you should be redirected to the receipt page where you'll see evidence of the purchase. Log in to your dashboard at Stripe and check that the test payment was successful https://dashboard.stripe.com/test/dashboard.

    ---

    Now that we're taking payments successfully for products – albeit rather boring and somewhat anonymous products – let's take care of payment failures.

    ###Error handling

    Try making a payment with a test card that will be declined.
    https://stripe.com/docs/testing#cards

    ![Card Declined](https://raw.githubusercontent.com/tmcdb/stripe-tutorial-images/master/declined-card.png)

    A `Stripe::CardError` exception will be raised. Let's take a look at Stripe's API documentation again to see how they suggest we handle errors:

    https://stripe.com/docs/api#errors

    We can rescue errors from our model and do something useful with them:

    ```ruby
    # app/controllers/orders_controller.rb
    def create
    @product = Product.find(params[:product_id])
    @order = @product.orders.new(order_params)
    if @order.save
    Stripe.api_key = Rails.application.secrets.stripe_secret_key # set the secret key to identify with stripe.
    Stripe::Charge.create(
    :amount => @product.price_in_pence,
    :currency => "gbp",
    :card => @order.stripe_token # obtained with Stripe.js
    )
    flash[:success] = "Thanks for purchasing #{@product.name}"
    redirect_to product_order_path(@product, @order)
    else
    flash[:error] = "Oops, something went wrong"
    render :new
    end
    rescue Stripe::CardError => e
    body = e.json_body
    err = body[:error]
    flash[:error] = err[:message]
    render :new
    end
    ```

    The code between rescue and end only executes if the app tries to raise the named exception. So if we type in the details again and the card is declined the error message will be passed to the flash hash and the form will be rendered again.

    Let's display the flash messages in the browser with some code in the application layout view:

    ```HTML+ERB
    # app/views/layouts/application.html.erb
    <html>
    #...
    <body>
    <% flash.each do |key, value| %>
    <div class="<%= key %>">
    <p><%= value %></p>
    </div>
    <% end %>
    <%= yield %>
    </body>
    </html>
    ```

    Now if we submit the `4000 0000 0000 0002` card details, we'll be redirected to the form along with an error message.


    ### Heroku Deployment

    Once you've downloaded the [Herkou toolbelt](http://toolbelt.heroku.com) it's dead easy to Deploy to heroku. The toolbelt gives you a suite of commands to issue on the command line.

    ```bash
    $ heroku login
    ```
    ```irb
    Enter your Heroku credentials.
    Email: [email protected]
    Password:
    Could not find an existing public key.
    Would you like to generate one? [Yn]
    Generating new SSH public key.
    Uploading ssh public key /Users/adam/.ssh/id_rsa.pub
    ```
    ```bash
    $ heroku create
    ```
    ```irb
    Creating desolate-meadow-9247... done, stack is cedar
    http://desolate-meadow-9247.herokuapp.com/ | [email protected]:desolate-meadow-9247.gito
    Git remote heroku added
    ```
    ```bash
    $ heroku open
    ```

    ![$ heroku open](https://raw.githubusercontent.com/tmcdb/stripe-tutorial-images/master/heroku-open.png)

    ### Settings

    There are some Gems we need for deploying to Heroku with Rails 4.

    ```ruby
    group :development, :test do
    gem 'sqlite3'
    end
    group :production do
    gem 'rails_12factor'
    gem 'pg'
    end
    ruby '2.1.2'
    ```
    ```bash
    $ bundle install
    ```

    The `rails_12factor` Gem handles some configuration necessary for running a Rails app on Heroku. The `pg` Gem is the Ruby interface to PostgreSQL, which is the database required for a Rails app running on Heroku, so wrap `gem 'sqlite3'` in a block specefying development and test environments and use `gem 'pg'` in your production enviroment.

    > For info on dev/prod parity see [here](https://gist.github.com/tmcdb/6aa96a88d7e2355a6b2b).

    ```bash
    $ git add -A .
    $ git commit -m 'heroku config'
    $ git push origin master
    ```
    ```irb
    Counting objects: 232, done.
    Delta compression using up to 4 threads.
    Compressing objects: 100% (198/198), done.
    Writing objects: 100% (211/211), 22.31 KiB | 0 bytes/s, done.
    Total 211 (delta 102), reused 0 (delta 0)
    To [email protected]:tmcdb/paymental.git
    67e173a..83fd83e master -> master
    ```
    ```bash
    $ git push heroku master
    ```

    Reload your app in the browser and notice the error page.

    ![Heroku Error](https://raw.githubusercontent.com/tmcdb/stripe-tutorial-images/master/heroku-error.png)

    We can't see the cause of the error in the browser but we can debug it at the command line.

    ```bash
    $ heroku logs
    ```
    ```irb
    ...
    2014-10-22T17:41:28.158729+00:00 app[web.1]: PG::UndefinedTable: ERROR: relation "products" does not exist
    ...
    ```

    The exception is a `PG::UndefinedTable` exception. This tells me that I need to rake the database on the server.

    Heroku lets us connect to the server and run commands just as we would locally with `herkou run`.

    ```bash
    $ heroku run rake db:migrate
    ```
    ```irb
    Running `rake db:migrate` attached to terminal... up, run.9289
    Migrating to CreateProducts (20141015130457)
    == 20141015130457 CreateProducts: migrating ===================================
    -- create_table(:products)
    -> 0.0381s
    == 20141015130457 CreateProducts: migrated (0.0383s) ==========================

    Migrating to CreateOrders (20141015131508)
    == 20141015131508 CreateOrders: migrating =====================================
    -- create_table(:orders)
    -> 0.0176s
    == 20141015131508 CreateOrders: migrated (0.0178s) ============================

    ```
    Reloading the browser now should give us access to the live app!
    ### Stripe Live Keys
    Earlier on we set our Stripe test keys for connecting to Stripe's test API. In order to take real payments on our app we need to identify ourselves with Stripe using our live keys available [here](https://dashboard.stripe.com/account/apikeys).
    ```yml
    # config/secrets.yml

    # Do not keep production secrets in the repository,
    # instead read values from the environment.
    production:
    secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
    stripe_secret_key: <%= ENV["STRIPE_SECRET_KEY"] %>
    stripe_public_key: <%= ENV["STRIPE_PUBLIC_KEY"] %>
    ```
    Each key is a reference to an environment variable. We can set them easily on the command line with the Heroku toolbelt.
    ```bash
    $ heroku config:set STRIPE_SECRET_KEY=sk_foo STRIPE_PUBLIC_KEY=pk_bar
    ```

    Alternatively you can set them in the browser by visiting the [Heroku dashboard](https://dashboard.heroku.com/apps), selecting your app, navigating to the settings tab, clicking "Reveal Config Vars", clicking "Edit", and typing in the new key-value pair at the bottom of the list (it goes without saying that the command line wins every time).

    Providing you've activated your Stripe account with your bank account details your app should now be ready to accept real payments.

    Hopefully you found this tutorial useful. Let me know your thoughts at [[email protected]](mailto:[email protected]).

    To see how to refactor the Charge code into a model or concern to keep the controllers and views cleaner have a [look here](https://gist.github.com/tmcdb/066f08e2622e0c06b23a).