Building a React Application
March 14, 2017

We’re going to put together a single page React application, composed of multiple Components. We’ll setup this project using a combination of Node and Webpack. For quickly adding front-end styling, we will use Semantic UI.

Features

Setup

Create project directory

$ mkdir projectName && cd projectName

Initialize Git/GitHub

$ git init
$ git create
$ echo "# projectName" > README.md
$ git add . && git commit -m "Initial commit" && git push origin master && git browse
$ git branch --set-upstream-to=origin/master master
$ git pull origin master

git create and git browse commands are available via hub.

Add .gitignore

$ touch .gitignore

.gitignore

/node_modules
/dist
/npm-debug.log

Install NPM modules

Generate package.json

$ npm init

package.json

{
  "name": "projectName",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "npm run build",
    "build": "webpack -d && cp src/index.html dist/index.html && webpack-dev-server --content-base src/ --inline --hot",
    "build:prod": "webpack -d && cp src/index.html dist/index.html"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/username/projectName.git"
  },
  "author": "Real Name <email@email.com>",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/username/projectName/issues"
  },
  "homepage": "https://github.com/username/projectName#readme",
  "dependencies": {
    "react": "^15.4.2",
    "react-dom": "^15.4.2"
  },
  "devDependencies": {
    "babel-core": "^6.24.0",
    "babel-loader": "^6.4.0",
    "babel-preset-es2015": "^6.24.0",
    "babel-preset-react": "^6.23.0",
    "babel-preset-stage-2": "^6.22.0",
    "webpack": "^2.2.1",
    "webpack-dev-server": "^2.4.2"
  }
}

I prefer the MIT License because it is the simplest and most popular free software license.

Install React dependencies

$ npm install react react-dom --save

Install Webpack dependencies

$ npm install webpack webpack-dev-server babel-core babel-loader babel-preset-es2015 babel-preset-react babel-preset-stage-2 css-loader less-loader --save-dev

Create file structure

Install Semantic UI

Create src folder containing app

$ mkdir src
$ mkdir src/app
$ mkdir src/app/components

Add webpack config

$ touch webpack.config.js src/index.html src/app/index.js

webpack.config.js

var path = require("path");
var webpack = require("webpack");

var DIST_DIR = path.resolve(__dirname, "dist");
var SRC_DIR = path.resolve(__dirname, "src");

var config = {
    entry: SRC_DIR + "/app/index.js",
    output: {
        path: DIST_DIR + "/app",
        filename: "bundle.js",
        publicPath: "/app/"
    },
    module: {
        loaders: [
            {
                test: /\.(eot|woff|woff2|ttf|svg|png|jpe?g|gif)(\?\S*)?$/,
                loader: 'url-loader?limit=100000&name=[name].[ext]'
            },
            {
                test: /\.css$/,
                loader: 'style-loader!css-loader'
            },
            {
                test: /\.jsx?$/,
                include: SRC_DIR,
                exclude: /node_modules/,
                loader: "babel-loader",
                query: {
                    presets: ["es2015", "react", "stage-2"]
                }
            }
        ]
    },
    resolve: {
        extensions: ['.js', '.jsx']
    }
}

module.exports = config;

src/index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title>projectName</title>
  <script
    src="https://code.jquery.com/jquery-3.1.1.min.js"
    integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
    crossorigin="anonymous"></script>
</head>
<body>
<div id="app"></div>
<script src="/app/bundle.js"></script>
</body>
</html>

src/app/index.js

import React from "react";
import { render } from "react-dom";

require('../../semantic/dist/semantic.min.js');
require('../../semantic/dist/semantic.min.css');

import { Header } from "./components/Header";
import { Home } from "./components/Home";

class App extends React.Component {
  render() {
    return (
      <div className="ui container">
        <Header/>
        <Home/>
      </div>
    );
  }
}

render(<App/>, window.document.getElementById("app"));

$(document).ready(function() {
  $('.ui.dropdown')
    .dropdown()
  ;
});

src/app/components/Header.jsx

import React from "react";

export class Header extends React.Component {
  render() {
    return(
      <nav className="ui text menu">
        <div className="ui dropdown icon item">
          <i className="wrench icon"></i>
          <div className="menu">
            <div className="item">
              <i className="dropdown icon"></i>
              <span className="text">New</span>
              <div className="menu">
                <div className="item">Document</div>
                <div className="item">Image</div>
              </div>
            </div>
            <div className="item">
              Open...
            </div>
            <div className="item">
              Save...
            </div>
            <div className="item">Edit Preferences</div>
            <div className="divider"></div>
            <div className="header">
              Export
            </div>
            <div className="item">
              Share...
            </div>
          </div>
        </div>

        <div className="right menu">
          <div className="ui right aligned category search item">
            <div className="ui transparent icon input">
              <input className="prompt" type="text" placeholder="Search videos..."></input>
              <i className="search link icon"></i>
            </div>
            <div className="results"></div>
          </div>
        </div>
      </nav>
    );
  }
}

src/app/components/Home.jsx

import React from "react";

export class Home extends React.Component {
  render() {
    return(
      <div>
        <h1>HOME</h1>
      </div>
    );
  }
}

Add open-source files

$ touch LICENSE.txt CONTRIBUTING.md AUTHORS.md

LICENSE.txt

Copyright <YEAR> <COPYRIGHT HOLDER>

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

README.md

# projectName

CONTRIBUTING.md

## Contributing

0. Fork it
0. Create a feature branch: `git checkout -b feature-something-useful`
0. Add yourself to the `AUTHORS.md` file
0. Commit your changes: `git commit -am 'Add useful feature'`
0. Push to the branch: `git push origin feature-something-useful`
0. Submit a pull request

AUTHORS.md

## Authors

- **Real Name** - [@username](https://github.com/username)

Start development server

$ npm start

Project will run by default on http://localhost:8080/

Building a Rails 5 App
February 01, 2017

We’re going to put together a basic web application using Rails, describing the app in terms of Features and of User Stories.

User Stories

Users can sign up, login, view their profile page and logout.

Users can view a list of Pets and the Toys that belong to each Pet.

Pets can be edited.

Users can see a Pet’s information.

Users can click on a link to show a Pet’s Toys via AJAX.

Features

Setup

Create rails project

$ rails new pet_project && cd pet_project

Add/update required gems

Gemfile

gem 'hirb'
gem 'faker'
gem 'bcrypt'
gem 'rspec-rails'

Bundle, create database

$ bundle && rails db:create

Models

Generate models

$ rails generate model Pet name:string breed:string age:integer cute:boolean --no-test-framework
$ rails generate model Toy description:text pet:references --no-test-framework
$ rails generate model User name:string email:string:uniq password_digest:string --no-test-framework

null and default cannot be specified from the command line, add them to the migrations as necessary. documentation

Edit migrations

db/migrate/[timestamp]_create_pets.rb

class CreatePets < ActiveRecord::Migration[5.0]
  def change
    create_table :pets do |t|
      t.string :name, null: false
      t.string :breed, null: false
      t.integer :age, null: false
      t.boolean :cute, null: false

      t.timestamps
    end
  end
end

db/migrate/[timestamp]_create_toys.rb

class CreateToys < ActiveRecord::Migration[5.0]
  def change
    create_table :toys do |t|
      t.text :description, null: false
      t.references :pet, foreign_key: true

      t.timestamps
    end
  end
end

db/migrate/[timestamp]_create_users.rb

class CreateUsers < ActiveRecord::Migration[5.0]
  def change
    create_table :users do |t|
      t.string :name, null: false
      t.string :email, null: false
      t.string :password_digest, null: false

      t.timestamps
    end
    add_index :users, :email, unique: true
  end
end

Migrate, Seed database

$ rails db:migrate && rails db:seed

Active Record associations

app/models/pet.rb

class Pet < ApplicationRecord
  has_many :toys, inverse_of: :pet

  validates_presence_of :name, :breed, :age
  validates_inclusion_of :cute, :in => [true, false], message: "must be true or false"
  validates_numericality_of :age
end

app/models/toy.rb

class Toy < ApplicationRecord
  belongs_to :pet, inverse_of: :toys

  validates_presence_of :description
end

app/models/user.rb

class User < ApplicationRecord
  has_secure_password
  before_save { self.email = email.downcase }
  validates :name, presence: true, length: { maximum: 50 }
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
  validates :email, presence: true, length: { maximum: 255 },
                    format: { with: VALID_EMAIL_REGEX },
                    uniqueness: { case_sensitive: false }
  validates :password, presence: true, length: { minimum: 6 }
end

Rollback models (if necessary)

$ rails destroy model Pet --no-test-framework
$ rails destroy model Toy --no-test-framework
$ rails destroy model User --no-test-framework

Routing

config/routes.rb

Rails.application.routes.draw do
  resources :sessions, only: [:new, :create, :destroy]
  get '/login' => 'sessions#new'
  post '/login' => 'sessions#create'
  get '/logout' => 'sessions#destroy'

  resources :users, only: [:new, :create, :show]
  get '/profile' => 'users#show'
  get '/signup' => 'users#new'

  resources :pets, only: [:index, :edit, :update, :show]  do
    resources :toys, only: [:index]
  end

  root 'pets#index'
  get '/home' => "pets#index"
end

Helpers

app/helpers/users_helper.rb

module UsersHelper
  def current_user
    @current_user ||= User.find(session[:user_id]) if session[:user_id]
  end

  def authorize
    redirect_to login_path unless current_user
  end
end

Controllers

Generate controllers

$ rails generate controller Pets index show edit update --no-controller-specs --no-view-specs --no-helper --no-assets
$ rails generate controller Toys index --no-controller-specs --no-view-specs --no-helper --no-assets
$ rails generate controller Sessions new create destroy --no-controller-specs --no-view-specs --no-helper --no-assets
$ rails generate controller Users new create --no-controller-specs --no-view-specs --no-helper --no-assets

app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
  include UsersHelper
end

app/controllers/pets_controller.rb

class PetsController < ApplicationController
  def index
    @pets = Pet.all
  end

  def show
    @pet = Pet.find_by(id: params[:id])
    @toy = Toy.new(pet: @pet)
  end

  def edit
    @pet = Pet.find_by(id: params[:id])
  end

  def update
    @pet = Pet.find_by(id: params[:id])
    if @pet.update_attributes(pet_params)
      redirect_to pet_path
    else
      render 'edit'
    end
  end

private
  def pet_params
    params.require(:pet).permit(:name, :breed, :age, :cute)
  end
end

app/controllers/toys_controller.rb

class ToysController < ApplicationController
  def index
    @pet = Pet.find_by(id: params[:pet_id])
    @toys = @pet.toys

    respond_to do |format|
      format.html { render :index }
      format.js {}
    end
  end

private
  def toy_params
    params.require(:toy).permit(:description)
  end
end

app/controllers/sessions_controller.rb

class SessionsController < ApplicationController
  def new
    @user = User.new
  end

  def create
    @user = User.find_by_email(params[:email])
    if @user && @user.authenticate(params[:password])
      session[:user_id] = @user.id
      redirect_to root_path
    else
      render 'new'
    end
  end

  def destroy
    session[:user_id] = nil
    redirect_to root_path
  end

end

app/controllers/users_controller.rb

class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    if @user.save
      session[:user_id] = @user.id
      redirect_to root_path
    else
      render 'new'
    end
  end

private

  def user_params
    params.require(:user).permit(:name, :email, :password, :password_confirmation)
  end
end

Rollback controllers (if necessary)

$ rails destroy controller Pet
$ rails destroy controller Toy
$ rails destroy controller Session
$ rails destroy controller User

Views

Layouts

app/views/layouts/application.html.erb

<!DOCTYPE html>
<html>
  <head>
    <title>Dog & Pony Show</title>
    <%= csrf_meta_tags %>

    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <% if current_user %>
      <%= link_to "#{current_user.name}", profile_path, class: "item" %>
      <%= link_to "Logout", logout_path,  class: "item" %>
    <% else %>
      <%= link_to 'Login', login_path, class: "item" %>
      <%= link_to 'Signup', signup_path, class: "item" %>
    <% end %>
    <%= yield %>
  </body>
</html>

Pets

app/views/pets/_pet.html.erb

<li><%= link_to pet.name, pet_path(pet) %></li>

app/views/pets/edit.html.erb

<h1>Edit <%= @pet.name %></h1>
  <%= form_for([@pet]) do |f| %>

    <% if @pet.errors.any? %>
      <h2><%= pluralize(@pet.errors.count, "error") %> prohibited this post from being saved:</h2>
      <ul>
        <% @pet.errors.full_messages.each do |msg| %>
          <li><%= msg %></li>
        <% end %>
      </ul>
    <% end %>

    Name: <%= f.text_field :name%> <br>

    Cute? <%= f.text_field :cute, placeholder: "cute?" %><br>
    Age: <%= f.text_field :age, placeholder: "age" %><br>
    Breed: <%= f.text_field :breed, placeholder:"breed" %><br>
    <%= f.submit "Submit pet" %>
<% end %>

app/views/pets/index.html.erb

<h1>Pets</h1>

<ul>
<%= render partial: "pet", collection: @pets %>
</ul>

app/views/pets/show.html.erb

<h1><%= @pet.name %></h1>

<ul>
  <li>Breed: <%=@pet.breed %></li>
  <li>Age:  <%=@pet.age %></li>
  <li>Cute: <%=@pet.cute %></li>
</ul>

<%= link_to "Edit #{@pet.name}", edit_pet_path(@pet) %>

<%= link_to 'Show Toys', pet_toys_path(@pet), remote: true %>
<div class="show-toys">
</div>

Toys

app/views/toys/_toys.html.erb

<%= @pet.name %>'s' toys:
<ul>
  <% @toys.each do |toy| %>
    <li>
      <%= toy.description %>
    </li>
  <% end %>
</ul>

app/views/toys/index.html.erb

<%= @pet.name %>'s' toys:
<ul>
  <% @toys.each do |toy| %>
    <li>
      <%= toy.description %>
    </li>
  <% end %>
</ul>

app/views/toys/index.js.erb

$(".show-toys").html("<%= j render partial: 'toys', locals: { toys: @toys } %>")

Sessions

app/views/sessions/new.html.erb

<h1>Login</h1>

<% if not @user %>
  <span class='error'>Email/password is incorrect</span><br><br>
<% end %>

<%= form_tag '/login' do %>
  Email: <%= text_field_tag :email %>
  Password: <%= password_field_tag :password %>
  <%= submit_tag "Submit" %>

<% end %>

Users

app/views/users/new.html.erb

<h1>Sign up</h1>

<%= form_for @user, url: '/users' do |f| %>
  <% if @user.errors.any? %>
    <h2><%= pluralize(@user.errors.count, "error") %> prohibited this post from being saved:</h2>
    <ul>
      <% @user.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
    </ul>
  <% end %>

  Name: <%= f.text_field :name %>
  Email: <%= f.text_field :email %>
  Password: <%= f.password_field :password %>
  Password Confirmation: <%= f.password_field :password_confirmation %>
  <%= f.submit "Submit" %>

<% end %>

app/views/users/show.html.erb

<h1><%= current_user.name %></h1>
<h2><%= current_user.email %></h2>

Tests

Generate model tests

$ rails generate model Pet --no-migration --test-framework=rspec --skip
$ rails generate model Toy --no-migration --test-framework=rspec --skip
$ rails generate model User --no-migration --test-framework=rspec --skip

Generate controller tests

$ rails generate controller Pet --no-migration --test-framework=rspec --skip
$ rails generate controller Toy --no-migration --test-framework=rspec --skip
$ rails generate controller Session --no-migration --test-framework=rspec --skip
$ rails generate controller User --no-migration --test-framework=rspec --skip

Fabric vs Invoke
January 17, 2017

Similar to Ruby’s Rake tool, Python has tools for running shell commands and defining/organizing tasks. My personal favorite of the bunch is Fabric, but for those using Python 3, you can consider using Invoke. These tools provide high level APIs for task execution.

Invoke

from invoke import task, run

@task
def count_files(ctx):
    """ Count files in project folder """
    ctx.run('sudo find . -print0 | xargs -0 -n 1 ls -id | cut -d" " -f1 | sort -u | wc -l')

Fabric

from fabric.api import *

@task
def count_files():
    with settings(warn_only=True):
        local('find . -print0 | xargs -0 -n 1 ls -id | cut -d" " -f1 | sort -u | wc -l')

Version Management Tools
December 26, 2016

If you’re working on multiple software projects, it is a good practice to use Version Management Tools to maintain consistency amongst and between different code bases.

In Ruby, for example, many developers manage their Ruby versions using using tools like rbenv and RVM.

I wanted to do a similar setup using Python and ended up settling on pyenv. Using pyenv, I was able to download specific versions of Python 2/3 and set both to be available globally.

Node has a similar tool, called nvm which has much of the same functionality as it’s counterparts.

Java, not to be outdone, has a tool called jenv.

If you had previously installed Python / Ruby / Node, you will need to remove the existing installations (excluding System installations, e.g. Python) and/or set the managed versions before the user-installed versions in your $PATH .

jenv does not install JDKs

pyenv

Install and configure pyenv

$ brew install pyenv
$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc
$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc
$ echo 'if which pyenv > /dev/null; then eval "$(pyenv init -)"; fi' >> ~/.bashrc
Test pyenv installations
$ pyenv install --list
Ensure ssl extension is compiled
$ brew uninstall openssl && brew install openssl
Install Python versions
$ CFLAGS="-I$(brew --prefix openssl)/include" LDFLAGS="-L$(brew --prefix openssl)/lib" env PYTHON_CONFIGURE_OPTS="--enable-framework" pyenv install 2.7.14
$ CFLAGS="-I$(brew --prefix openssl)/include" LDFLAGS="-L$(brew --prefix openssl)/lib" env PYTHON_CONFIGURE_OPTS="--enable-framework" pyenv install 3.6.2
Set pyenv versions
# Python 2
$ pyenv global 2.7.14
$ pip2.7 install -U pip virtualenv virtualenvwrapper

# Python 3
$ pyenv global 3.6.2
$ pip3 install -U pip virtualenv virtualenvwrapper
Set Python 2/3 available globally
$ pyenv global 2.7.14 3.6.2

Install pyenv-virtualenv and pyenv-virtualenvwrapper as plugins

$ git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv
$ git clone https://github.com/yyuu/pyenv-virtualenvwrapper.git ~/.pyenv/plugins/pyenv-virtualenvwrapper
Test pyenv installations
$ pyenv versions
$ pyenv whence virtualenv virtualenvwrapper.sh
$ pyenv virtualenvs

rbenv

Install and configure rbenv

$ brew install rbenv
$ echo 'if which rbenv > /dev/null; then eval "$(rbenv init -)"; fi' >> ~/.bashrc
$ echo 'test -d "$HOME/.rbenv/" && PATH="$HOME/.rbenv/bin:$PATH" && PATH="$HOME/.rbenv/shims:$PATH"' >> ~/.bashrc
Install Ruby versions
$ rbenv install 2.4.2
$ rbenv install 2.3.1
Set rbenv versions
$ rbenv global 2.4.2
Test rbenv installations
$ rbenv versions

nvm

Install and configure nvm

$ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.2/install.sh | bash
Use system version for administering nvm
$ nvm use system
Set LTS version as default
$ nvm alias default lts/*
Install Node versions
$ nvm install --lts
Test nvm installations
$ nvm ls

jenv

Install and configure jenv

$ brew install jenv
$ echo 'export PATH="$HOME/.jenv/bin:$PATH"' >> ~/.bashrc
$ echo 'if which jenv > /dev/null; then eval "$(jenv init -)"; fi' >> ~/.bashrc
Add Java versions to jenv
$ jenv add /Library/Java/JavaVirtualMachines/jdk1.8.0_05.jdk/Contents/Home/
$ jenv add /Library/Java/JavaVirtualMachines/jdk1.8.0_144.jdk/Contents/Home/
Test jenv installations
$ jenv versions
Set jenv versions
$ jenv global 1.8.0_144