Monday, July 31, 2017

Heroku production version: all 14 chapters completed (no mail server)

For the production version, I completed all 14 chapters of Michael Hartl's Ruby on Rails tutorial (https://www.railstutorial.org/) on July 31, 2017. The chapter 11 and 12 are skipped, so the email server is disabled.

The source code of the project is:
https://github.com/jimmy2046/sample_app_heroku_2

The URL hosting address of Heroku production is:
https://warm-ravine-91766.herokuapp.com/

Switch back to Intel Core2 Quad 2.50GHz

Today, I decided to switch back to use my Dell desktop computer with Intel Core2 Quad 2.50GHz CPU and 64-bit Ubuntu Linux 16.04 for Ruby on Rails development. I had put my old laptop with Intel T2080 1.73GHz "into the closet".

Sunday, July 30, 2017

Heroku SendGrid Add-on

The Heroku SendGrid Add-on allows a website to send emails to their members and it does not charge money for 400 emails a day but it needs credit card verification. For current time being, I decided NOT to install the SendGrid add-on. For Heroku production hosting, I shall skip Chapter 11: Account Activation and Chapter 12: Password Reset. And I shall go directly to Chapter 13: User Microposts.

Installing Heroku on 32-bit Ubuntu Linux

For version control, Ubuntu Linux comes with pre-installed git. For production deployment, Heroku CLI needs to be installed in order to push a Ruby on Rails project to Heroku for hosting.

This was what I did on my 32-bit Ubuntu Linux laptop computer.

shell terminal
$ heroku version
heroku: command not found

$ wget -qO- https://cli-assets.heroku.com/install-ubuntu.sh | sh

$ heroku version
heroku-cli/6.13.5 (linux-x86) node-v8.2.1

After I had installed Heroku, I needed to log in and add my public SSH key.
shell terminal
$ heroku login
$ heroku keys:add

Reference:
Heroku CLI | Heroku Dev Center - Debian/Ubuntu
https://devcenter.heroku.com/articles/heroku-cli#debian-ubuntu

Heroku Installation Log on 64-bit Ubuntu (April 2017 version)

I did not post the log file of Heroku installation that I did in April 2017. I just kept it on a text file of my local hard drive. Now, I found Heroku has updated their installation procedure. So, I think that is worth to post what I did for my Heroku installation on my desktop running on 64-bit Ubuntu Linux.

Download the Heroku CLI for Debian/Ubuntu
# Run this from your terminal.
# The following will add our apt repository and install the CLI:

sudo add-apt-repository "deb https://cli-assets.heroku.com/branches/stable/apt ./"
curl -L https://cli-assets.heroku.com/apt/release.key | sudo apt-key add -
sudo apt-get update
sudo apt-get install heroku
shell terminal
jimmyc@Jimmy-C-2017:~/gettingstarttedwithrails$ heroku login
Enter your Heroku credentials:
Email: jimmychong_st@yahoo.com
Password:
Logged in as jimmychong_st@yahoo.com
jimmyc@Jimmy-C-2017:~/gettingstarttedwithrails$ heroku keys:add
Found an SSH public key at /home/jimmyc/.ssh/id_rsa.pub
? Would you like to upload it to Heroku? Yes
Uploading /home/jimmyc/.ssh/id_rsa.pub SSH key... done
jimmyc@Jimmy-C-2017:~/gettingstarttedwithrails$ heroku create
Creating app... done, ⬢ immense-cove-17163
https://immense-cove-17163.herokuapp.com/ | https://git.heroku.com/immense-cove-17163.git
jimmyc@Jimmy-C-2017:~/gettingstarttedwithrails$

Installing PostgreSQL database for my 32-bit Linux laptop

I did not aware that, in production environment, Heroku uses PostgreSQL database. Therefore, if I want to deploy the Ruby on Rails project on Heroku, I have to install PostgreSQL on my 32-bit Linux laptop as well.

The procedure for installing PostgreSQL on Ubuntu Linux is explained on GoRails:
https://gorails.com/setup/ubuntu/16.04#postgresql

Setup Ruby On Rails on Laptop

Today, I installed Ruby on Rails on my Dell laptop running on Ubuntu Linux 16.04 (32-bit/i386). I just following the instructions on GoRails (https://gorails.com/setup/ubuntu/16.04) and everything seemed going smoothly. I also generated a new RSA SSH key in my laptop for Github account. So, my Github account has 2 public keys one. One key is for my desktop and another one is for my laptop computer. For my laptop, I just use the default Sqlite database and I did NOT install MySQL for my laptop. Because I think that I won't host the Ruby on Rails server and the database in a laptop computer.

Update: I have to install PostgreSQL database for Heroku production environment. Please see my next article. 


References:
Setup Ruby On Rails on Ubuntu 16.04 Xenial Xerus
https://gorails.com/setup/ubuntu/16.04


Saturday, July 29, 2017

Installing 32-bit Ubuntu Linux 16.04 on Dell Inspiron 6400 Laptop

I have an old Dell Inspiron 6400 laptop which I bought around ten years ago (2007). It was put in my bookshelf. I rarely touch it and I keep it as a secondary spare computer. Once upon a time, the LCD screen was broken due to excessive pressure. So, I changed the LCD screen once by myself. Originally, the laptop came with a built-in Wi-fi and it had been working good for many year. However, yesterday I realized that the built-in Wi-fi was broken down and it does not work anymore. Therefore, I have to plug in using Ethernet cable to use wired Ethernet to connect to the Internet instead.

The Ubuntu Linux DVD ISO images can be download on this URL:
http://releases.ubuntu.com/16.04/

As of time of writing (July 2017), there are 64-bit and 32-bit version of Ubuntu Linux 16.04 Desktop DVD ISO image:
  • ubuntu-16.04.2-desktop-amd64.iso
  • ubuntu-16.04.2-desktop-i386.iso

I thought that my Dell laptop could support the 64-bit version but it couldn't. During the installation, the system prompted:
Kernel requires an x86-64 CPU, but only detected an i686 CPU.

Ubuntu did not put the 32-bit version conspicuously, I found the 32-bit version by search something like this on Google:
google: ubuntu 16.04 i386

As I read the webpage, http://releases.ubuntu.com/16.04/, it states that:

32-bit PC (i386) desktop image
  •     For almost all PCs. This includes most machines with Intel/AMD/etc type processors and almost all computers that run Microsoft Windows, as well as newer Apple Macintosh systems based on Intel processors.

It labeled the 32-bit version as "i386". I was thinking that does the 32-bit version support very old computers such as Intel 386? Would it support my older computers such as such as the Celeron 300, the Pentium 75 or even the 80486SX that I put the motherboard, CPU, and RAM in my storage? Would it be very slow?

And then, I downloaded the 32-bit ISO image and used Roxio to burn a DVD disc. The installation procedures are almost identical between the 64-bit (AMD64) and the 32-bit (i386) versions of Ubuntu Linux. For the allocation of disk space of my old laptop (https://tutorials.ubuntu.com/tutorial/tutorial-install-ubuntu-desktop#5), I would prefer to erase (format) everything on the old hard drive and Windows Vista to make the Ubuntu installation goes more smoothly. The installation was pretty straight forward, I just left the default setting "as is", clicked OK and go.

Finally, the installation completed successfully and this was the system configuration of the "About this computer" command:
  • Ubuntu 16.04 LTS
  • Memory: 2.0 GiB
  • Processor: Genuine Intel CPU T2080 @ 1.73GHz x 2
  • Graphic: Intel 945 x86/MMX/SSE2
  • OS type: 32-bit
  • Disk: 115.9 GB


References
Ubuntu 16.04.2 LTS (Xenial Xerus) - Ubuntu Releases
http://releases.ubuntu.com/16.04/

Install Ubuntu desktop tutorial - Ubuntu tutorials
https://tutorials.ubuntu.com/tutorial/tutorial-install-ubuntu-desktop#0

Monday, July 24, 2017

The transfer from development to production using Heroku

The first attempt was failed when I tried to push all the development codes from all 14 chapters to Heroku. When I digged into Heroku logs file, it did not specific the error. In Heroku log file, it stated "Heroku deployment error H10 App crashed" and it did not explain the details.

In order to make the development version could be applied to Heroku, I had to revert back the project version to chapter 3: "Finish static pages" and I replaced the original Gemfile that was regenerated automatically by Ruby on Rails new project command with Michael Hartl's customized Gemfile for Heroku that listed on Listing 3.2: A Gemfile for the sample app.

The production version had completed the first 10 chapters of Michael Hartl's book. As of time of writing, these files had to be changed in order to make it to deploy to Heroku production environment successfully.

sample_app_heroku_2/Gemfile
source 'https://rubygems.org'

gem 'rails',        '5.1.2'
gem 'bcrypt',         '3.1.11'
gem 'faker',          '1.7.3'
gem 'will_paginate',           '3.1.5'
gem 'bootstrap-will_paginate', '1.0.0'
gem 'bootstrap-sass', '3.3.7'
gem 'puma',         '3.9.1'
gem 'sass-rails',   '5.0.6'
gem 'uglifier',     '3.2.0'
gem 'coffee-rails', '4.2.2'
gem 'jquery-rails', '4.3.1'
gem 'turbolinks',   '5.0.1'
gem 'jbuilder',     '2.7.0'

group :development, :test do
  gem 'sqlite3', '1.3.13'
  gem 'byebug',  '9.0.6', platform: :mri
end

group :development do
  gem 'web-console',           '3.5.1'
  gem 'listen',                '3.0.8'
  gem 'spring',                '2.0.2'
  gem 'spring-watcher-listen', '2.0.1'
end

group :test do
  gem 'rails-controller-testing', '1.0.2'
  gem 'minitest-reporters',       '1.1.14'
  gem 'guard',                    '2.13.0'
  gem 'guard-minitest',           '2.4.4'
end

group :production do
  gem 'pg', '0.18.4'
end

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

sample_app_heroku_2/config/environments/production.rb
  config.force_ssl = true

sample_app_heroku_2/config/puma.rb
workers Integer(ENV['WEB_CONCURRENCY'] || 2)
threads_count = Integer(ENV['RAILS_MAX_THREADS'] || 5)
threads threads_count, threads_count

preload_app!

rackup      DefaultRackup
port        ENV['PORT']     || 3000
environment ENV['RACK_ENV'] || 'development'

on_worker_boot do
  # Worker specific setup for Rails 4.1+
  # See: https://devcenter.heroku.com/articles/
  # deploying-rails-applications-with-the-puma-web-server#on-worker-boot
  ActiveRecord::Base.establish_connection
end

sample_app_heroku_2/Procfile
web: bundle exec puma -C config/puma.rb
 
On the other hand, I made small changes to the View files and Database Seed file for personalization.

sample_app_heroku_2/app/views/static_pages/home.html.erb
<div class="center jumbotron">
  <h1>Welcome to the Jimmy App</h1>

  <h2>
    This is the home page for the
    <a href="http://www.railstutorial.org/">Ruby on Rails Tutorial</a>
    sample application.
  </h2>

  <%= link_to "Sign up now!", signup_path, class: "btn btn-lg btn-primary" %>
</div>

<%= link_to image_tag("rails.png", alt: "Rails logo"),
            'http://rubyonrails.org/' %>

sample_app_heroku_2/app/views/layouts/_header.html.erb
<header class="navbar navbar-fixed-top navbar-inverse">
  <div class="container">
    <%= link_to "jimmy app", root_path, id: "logo" %>
    <nav>
      <ul class="nav navbar-nav navbar-right">
        <li><%= link_to "Home",   root_path %></li>
        <li><%= link_to "Help",   help_path %></li>       
        <% if logged_in? %>         
          <li><%= link_to "Users", users_path %></li>                   
          <li class="dropdown">
            <a href="#" class="dropdown-toggle" data-toggle="dropdown">
              Account <b class="caret"></b>
            </a>
            <ul class="dropdown-menu">
              <li><%= link_to "Profile", current_user %></li>
              <li><%= link_to "Settings", edit_user_path(current_user) %></li>
              <li class="divider"></li>
              <li>
                <%= link_to "Log out", logout_path, method: :delete %>
              </li>
            </ul>
          </li>
        <% else %>
          <li><%= link_to "Log in", login_path %></li>
        <% end %>
         
      </ul>
    </nav>
  </div>
</header>

sample_app_heroku_2/db/seeds.rb
User.create!(name:  "Example User",
             email: "example@railstutorial.org",
             password:              "secret",
             password_confirmation: "secret",
             admin: true)

99.times do |n|
  name  = Faker::Name.name
  email = "example-#{n+1}@railstutorial.org"
  password = "password"
  User.create!(name:  name,
               email: email,
               password:              password,
               password_confirmation: password)
end

* The Github repository for the Heroku production is https://github.com/jimmy2046/sample_app_heroku_2

* The production website in Heroku is https://warm-ravine-91766.herokuapp.com/

Deploy Michael Hartl's sample_app to Heroku

Deploy Michael Hartl's sample_app to Heroku Log

shell terminal: fetched the project from Github and stored in sample_app_heroku_2
$ cd ~
$ git clone https://github.com/jimmy2046/sample_app.git sample_app_heroku_2
* Showing Github remote origin for push and fetch
$ cd sample_app_heroku_2
$ git remote show origin
* remote origin
Fetch URL: https://github.com/jimmy2046/sample_app.git
Push URL: https://github.com/jimmy2046/sample_app.git

IMPORTANT
* Change Git remote push and fetch locations to: sample_app_heroku_2.git
$ git remote set-url origin https://github.com/jimmy2046/sample_app_heroku_2.git

* Git show origin
$ git remote show origin
* remote origin
  Fetch URL: https://github.com/jimmy2046/sample_app_heroku_2.git
  Push  URL: https://github.com/jimmy2046/sample_app_heroku_2.git
  HEAD branch: (unknown)
  Remote branches:
    refs/remotes/origin/master       stale (use 'git remote prune' to remove)
    refs/remotes/origin/static-pages stale (use 'git remote prune' to remove)
  Local branch configured for 'git pull':
    master merges with remote master

* Git show remote location:
$ git remote -v
origin    https://github.com/jimmy2046/sample_app_heroku_2.git (fetch)
origin    https://github.com/jimmy2046/sample_app_heroku_2.git (push)

* Git push to Github:
$ git push -u origin master
Username for 'https://github.com': jimmy2046
Password for 'https://jimmy2046@github.com':
Counting objects: 541, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (303/303), done.
Writing objects: 100% (541/541), 6.88 MiB | 728.00 KiB/s, done.
Total 541 (delta 205), reused 541 (delta 205)
remote: Resolving deltas: 100% (205/205), done.
To https://github.com/jimmy2046/sample_app_heroku_2.git
 * [new branch]      master -> master
Branch master set up to track remote branch master from origin.

* Bracket -> Change directory to -> sample_app_heroku_2

shell terminal
$ bundle install
$ rails db:migrate
$ rails db:seed
$ rails test
$ rails s -b 0.0.0.0 -p 3000

Firefox: http://localhost:3000/

$ git checkout -b attempt-heroku-deploy

sample_app_heroku_2/app/views/static_pages/home.html.erb
  <h1>Welcome to the Jimmy App</h1>

sample_app_heroku_2/app/views/layouts/_header.html.erb
    <%= link_to "jimmy app", root_path, id: "logo" %>

sample_app_heroku_2/db/seeds.rb
User.create!(name:  "Example User",
             email: "example@railstutorial.org",
             password:              "secret",
             password_confirmation: "secret",
             admin: true,
             activated: true,
             activated_at: Time.zone.now)

shell terminal
$ rails db:migrate:reset
$ rails db:seed

sample_app_heroku_2/Gemfile
source 'https://rubygems.org'

gem 'rails',        '5.1.2'

# bcrypt for password encription
gem 'bcrypt',         '3.1.11'

# faker for creating sample users for testing
gem 'faker',          '1.7.3'

# For Images
gem 'carrierwave',             '1.1.0'
gem 'mini_magick',             '4.7.0'
gem 'fog',                     '1.40.0'

# For pagination
gem 'will_paginate',           '3.1.5'
gem 'bootstrap-will_paginate', '1.0.0'

# Use Bookstrap
gem 'bootstrap-sass', '3.3.6'

gem 'puma',         '3.9.1'
gem 'sass-rails',   '5.0.6'
gem 'uglifier',     '3.2.0'
gem 'coffee-rails', '4.2.2'
gem 'jquery-rails', '4.3.1'
gem 'turbolinks',   '5.0.1'
gem 'jbuilder',     '2.7.0'

group :development, :test do
  gem 'sqlite3', '1.3.13'
  gem 'byebug',  '9.0.6', platform: :mri
end

group :development do
  gem 'web-console',           '3.5.1'
  gem 'listen',                '3.0.8'
  gem 'spring',                '2.0.2'
  gem 'spring-watcher-listen', '2.0.1'
end

group :test do
  gem 'rails-controller-testing', '1.0.2'
  gem 'minitest-reporters',       '1.1.14'
  gem 'guard',                    '2.13.0'
  gem 'guard-minitest',           '2.4.4'
end

group :production do
  gem 'pg', '0.18.4'
end

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

shell terminal
$ bundle install
$ bundle update
$ rails test

restart server
Ctrl + C
$ rails s -b 0.0.0.0 -p 3000

shell terminal for Github
$ rails test
$ git add -A
$ git commit -m "Ch2 Changed Gemfile for heroku"
$ git checkout master
$ git merge attempt-heroku-deploy
$ git remote -v
$ git push

shell terminal for heroku
$ heroku create
Creating app... done, ⬢ warm-ravine-91766
https://warm-ravine-91766.herokuapp.com/ | https://git.heroku.com/warm-ravine-91766.git

$ git push heroku master
$ heroku open

Firefox: https://warm-ravine-91766.herokuapp.com/

$ heroku logs
* The log of Ch 3:
$ git log
commit 614bdc6e9c49d6e73b2c2c96865461e9455d38cf
Author: jimmy2046 <jimmychong_st@yahoo.com>
Date:   Sun Apr 23 15:12:01 2017 -0700

    Finish static pages


$ git checkout -b old-state 614bdc6e9

Firefox: http://localhost:3000/

sample_app_heroku_2/Gemfile
source 'https://rubygems.org'

gem 'rails',        '5.1.2'
gem 'puma',         '3.9.1'
gem 'sass-rails',   '5.0.6'
gem 'uglifier',     '3.2.0'
gem 'coffee-rails', '4.2.2'
gem 'jquery-rails', '4.3.1'
gem 'turbolinks',   '5.0.1'
gem 'jbuilder',     '2.7.0'

group :development, :test do
  gem 'sqlite3', '1.3.13'
  gem 'byebug',  '9.0.6', platform: :mri
end

group :development do
  gem 'web-console',           '3.5.1'
  gem 'listen',                '3.0.8'
  gem 'spring',                '2.0.2'
  gem 'spring-watcher-listen', '2.0.1'
end

group :test do
  gem 'rails-controller-testing', '1.0.2'
  gem 'minitest-reporters',       '1.1.14'
  gem 'guard',                    '2.13.0'
  gem 'guard-minitest',           '2.4.4'
end

group :production do
  gem 'pg', '0.18.4'
end

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

shell terminal
$ cd sample_app_heroku_2
$ bundle update
$ bundle install --without production
$ bundle update
$ rails test
$ git commit -m "Ch3-Update-Gemfile-for-Heroku"

$ git branch
  attempt-heroku-deploy
  ch7-add-puma
  master
* old-state
  use-ch-3-Gemfile

$ git push old-state
$ git push heroku old-state

$ git branch
  attempt-heroku-deploy
  ch7-add-puma
  master
* old-state
  use-ch-3-Gemfile

$ git checkout master
$ git merge old-state

$ git status
$ git add -A
$ git commit -m "Ch3 Updated Gemfile v2"
$ git checkout old-state
* I had to disregard the master branch and replace with the "old-state" branch.
$ git merge master --strategy=ours
$ git checkout master

$ git remote -v
heroku    https://git.heroku.com/warm-ravine-91766.git (fetch)
heroku    https://git.heroku.com/warm-ravine-91766.git (push)
origin    https://github.com/jimmy2046/sample_app_heroku_2.git (fetch)
origin    https://github.com/jimmy2046/sample_app_heroku_2.git (push)

$ git push
$ git branch
$ git merge old-state
$ git push
$ rails test
$ git push heroku


$ git log
commit 0d158c0c37e61f494edfa92d206552d22fe6d9d7
Author: jimmy2046 <jimmychong_st@yahoo.com>
Date:   Wed May 10 18:12:07 2017 -0700

    Finish layout and routes

$ git checkout -b ch5-old-state 0d158c0c3
Firefox: http://localhost:3000/
$ rails test

sample_app_heroku_2/Gemfile
source 'https://rubygems.org'

gem 'rails',        '5.1.2'
gem 'bootstrap-sass', '3.3.7'
gem 'puma',         '3.9.1'
gem 'sass-rails',   '5.0.6'
gem 'uglifier',     '3.2.0'
gem 'coffee-rails', '4.2.2'
gem 'jquery-rails', '4.3.1'
gem 'turbolinks',   '5.0.1'
gem 'jbuilder',     '2.7.0'

group :development, :test do
  gem 'sqlite3', '1.3.13'
  gem 'byebug',  '9.0.6', platform: :mri
end

group :development do
  gem 'web-console',           '3.5.1'
  gem 'listen',                '3.0.8'
  gem 'spring',                '2.0.2'
  gem 'spring-watcher-listen', '2.0.1'
end

group :test do
  gem 'rails-controller-testing', '1.0.2'
  gem 'minitest-reporters',       '1.1.14'
  gem 'guard',                    '2.13.0'
  gem 'guard-minitest',           '2.4.4'
end

group :production do
  gem 'pg', '0.18.4'
end

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

$ bundle update
$ git status
$ git add -A
$ git commit -m "Ch5 Updated Gemfile for Heroku"
$ git branch
  attempt-heroku-deploy
* ch5-old-state
  ch7-add-puma
  master
  old-state
  use-ch-3-Gemfile

$ git merge -s ours master
$ git checkout master
$ git merge ch5-old-state
$ rails test
$ git push
$ git push heroku

=============================================
Ch 6:
$ git log
commit 3a0c190033fc6aef7316fdb0bc37ac7f05c21190
Author: jimmy2046 <jimmychong_st@yahoo.com>
Date:   Sun May 14 19:37:25 2017 -0700

    Make a basic User model (including secure passwords)

$ git checkout -b ch6-old-state 3a0c19003

sample_app_heroku_2/Gemfile
gem 'bcrypt',         '3.1.11'

$ bundle update
$ git status
$ git add -A
$ git commit -m "Ch6 Updated Gemfile for Heroku"
$ git branch
* ch6-old-state
master

$ git merge -s ours master
$ git checkout master
$ git merge ch6-old-state
$ rails test
$ git push
$ rails test
$ git push heroku
$ heroku run rails db:migrate

=============================================
Ch 7:

$ git log
commit 5ab58709367a7ad82bbb0852e301b081d255bc9c
Author: jimmy2046 <jimmychong_st@yahoo.com>
Date:   Wed May 24 17:45:19 2017 -0700

    Finish user signup

$ git checkout -b ch7-old-state 5ab587093
* I updated Gemfile in Brackets and saved the file
$ bundle update
$ rails test

config/environments/production.rb
  config.force_ssl = true

Procfile
web: bundle exec puma -C config/puma.rb

$ rails test
$ git status
$ rails test
$ git add -A
$ git commit -m "Ch7 Updated Gemfile for Heroku"
$ git merge -s ours master
$ git checkout master
$ git branch
$ git merge ch7-old-state
$ bundle update
$ rails test
$ git push
$ git push heroku
$ heroku run rails db:migrate

=============================================
Ch 10:

$ git log
commit 3aa04f3052aef91541aa7aef8378e156f557dc37
Author: jimmy2046 <jimmychong_st@yahoo.com>
Date:   Sat Jul 15 18:36:22 2017 -0700

    Finish user edit, update, index, and destroy actions

$ git checkout -b ch10-old-state 3aa04f305

* I updated: Gemfile, puma.rb, and production.rb files.

$ git status
$ git add -A
$ git commit -m "Chapter 10 Updated Gemfile for Heroku"
$ git merge -s ours master
$ git checkout master
$ git branch
$ git merge ch10-old-state
$ git push
$ rails test
$ git push heroku
$ heroku pg:reset DATABASE
$ heroku run rails db:migrate
$ heroku run rails db:seed
$ heroku restart

* As of time of writing, the production version had completed chapter 10 of Michael Hartl's book. The hosting URL on Heroku is:
https://warm-ravine-91766.herokuapp.com/

* The screen shot of production version on Heroku was:


References:
Change name of folder when cloning from github?
https://stackoverflow.com/questions/8570636/change-name-of-folder-when-cloning-from-github

How to replace master branch in git, entirely, from another branch? [duplicate]
https://stackoverflow.com/questions/2862590/how-to-replace-master-branch-in-git-entirely-from-another-branch

Make the current git branch a master branch
https://stackoverflow.com/questions/2763006/make-the-current-git-branch-a-master-branch

How can I determine the URL that a local Git repository was originally cloned from?
https://stackoverflow.com/questions/4089430/how-can-i-determine-the-url-that-a-local-git-repository-was-originally-cloned-fr

Changing a remote's URL
https://help.github.com/articles/changing-a-remote-s-url/

Change the URI (URL) for a remote Git repository
https://stackoverflow.com/questions/2432764/change-the-uri-url-for-a-remote-git-repository

2.5 Git Basics - Working with Remotes
https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes

Sunday, July 23, 2017

GoLang Ubuntu Linux Installation Log

GoLang Ubuntu Linux Installation Log

shell terminal
$ sudo apt-get install golang-go
$ cp .profile .profile_backup
$ sudo nano ~/.profile

.profile
export GOPATH=$HOME/work export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin

shell terminal
$ source ~/.profile
$ mkdir $HOME/work
$ mkdir -p work/src/github.com/jimmy2046/hello
$ nano ~/work/src/github.com/jimmy2046/hello/hello.go

hello.go
package main

import "fmt"

func main() {
    fmt.Printf("hello, world\n")
}

shell terminal
$ go install github.com/jimmy2046/hello
$ hello
$ which hello

References:
Ubuntu · golang/go Wiki · GitHub
https://github.com/golang/go/wiki/Ubuntu

How to Install Go 1.6 on Ubuntu 16.04
https://www.digitalocean.com/community/tutorials/how-to-install-go-1-6-on-ubuntu-16-04

GoLang Google Sheets API
https://developers.google.com/sheets/api/quickstart/go

Saturday, July 22, 2017

All Completed: Michael Hartl's Ruby on Rails Tutorial (Part 2)

sample_app Michael Hartl's Ruby on Rails Tutorial log

shell terminal
$ rails generate integration_test following

test/fixtures/relationships.yml
one:
  follower: michael
  followed: lana

two:
  follower: michael
  followed: malory

three:
  follower: lana
  followed: michael

four:
  follower: archer
  followed: michael

test/integration/following_test.rb
require 'test_helper'

class FollowingTest < ActionDispatch::IntegrationTest

  def setup
    @user = users(:michael)
    log_in_as(@user)
  end

  test "following page" do
    get following_user_path(@user)
    assert_not @user.following.empty?
    assert_match @user.following.count.to_s, response.body
    @user.following.each do |user|
      assert_select "a[href=?]", user_path(user)
    end
  end

  test "followers page" do
    get followers_user_path(@user)
    assert_not @user.followers.empty?
    assert_match @user.followers.count.to_s, response.body
    @user.followers.each do |user|
      assert_select "a[href=?]", user_path(user)
    end
  end
end

shell terminal
$ rails generate controller Relationships

test/controllers/relationships_controller_test.rb
require 'test_helper'

class RelationshipsControllerTest < ActionDispatch::IntegrationTest

  test "create should require logged-in user" do
    assert_no_difference 'Relationship.count' do
      post relationships_path
    end
    assert_redirected_to login_url
  end

  test "destroy should require logged-in user" do
    assert_no_difference 'Relationship.count' do
      delete relationship_path(relationships(:one))
    end
    assert_redirected_to login_url
  end   
   
end

app/controllers/relationships_controller.rb
class RelationshipsController < ApplicationController
  before_action :logged_in_user

  def create
    user = User.find(params[:followed_id])
    current_user.follow(user)
    redirect_to user
  end

  def destroy
    user = Relationship.find(params[:id]).followed
    current_user.unfollow(user)
    redirect_to user
  end

end

app/views/users/_follow.html.erb
<%= form_for(current_user.active_relationships.build, remote: true) do |f| %>
  <div><%= hidden_field_tag :followed_id, @user.id %></div>
  <%= f.submit "Follow", class: "btn btn-primary" %>
<% end %>

app/views/users/_unfollow.html.erb
<%= form_for(current_user.active_relationships.find_by(followed_id: @user.id),
             html: { method: :delete },
             remote: true) do |f| %>
  <%= f.submit "Unfollow", class: "btn" %>
<% end %>

app/controllers/relationships_controller.rb
class RelationshipsController < ApplicationController
  before_action :logged_in_user

  def create
    user = User.find(params[:followed_id])
    current_user.follow(user)
    respond_to do |format|
      format.html { redirect_to @user }
      format.js
    end
  end

  def destroy
    user = Relationship.find(params[:id]).followed
    current_user.unfollow(user)
    respond_to do |format|
      format.html { redirect_to @user }
      format.js
    end
  end

end

config/application.rb
require_relative 'boot'

require 'rails/all'

require File.expand_path('../boot', __FILE__)

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module SampleApp
  class Application < Rails::Application
    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration should go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded.
     
    # Include the authenticity token in remote forms.
    config.action_view.embed_authenticity_token_in_remote_forms = true
           
  end
end

test/integration/following_test.rb
require 'test_helper'

class FollowingTest < ActionDispatch::IntegrationTest

  def setup
    @user = users(:michael)
    @other = users(:archer)     
    log_in_as(@user)
  end

  test "following page" do
    get following_user_path(@user)
    assert_not @user.following.empty?
    assert_match @user.following.count.to_s, response.body
    @user.following.each do |user|
      assert_select "a[href=?]", user_path(user)
    end
  end

  test "followers page" do
    get followers_user_path(@user)
    assert_not @user.followers.empty?
    assert_match @user.followers.count.to_s, response.body
    @user.followers.each do |user|
      assert_select "a[href=?]", user_path(user)
    end
  end   

  test "should follow a user the standard way" do
    assert_difference '@user.following.count', 1 do
      post relationships_path, params: { followed_id: @other.id }
    end
  end

#  test "should follow a user with Ajax" do
#    assert_difference '@user.following.count', 1 do
#      post relationships_path, xhr: true, params: { followed_id: @other.id }
#    end
#  end

  test "should unfollow a user the standard way" do
    @user.follow(@other)
    relationship = @user.active_relationships.find_by(followed_id: @other.id)
    assert_difference '@user.following.count', -1 do
      delete relationship_path(relationship)
    end
  end

#  test "should unfollow a user with Ajax" do
#    @user.follow(@other)
#    relationship = @user.active_relationships.find_by(followed_id: @other.id)
#    assert_difference '@user.following.count', -1 do
#      delete relationship_path(relationship), xhr: true
#    end
#  end   
   
end

test/models/user_test.rb
  test "feed should have the right posts" do
    michael = users(:michael)
    archer  = users(:archer)
    lana    = users(:lana)
    # Posts from followed user
    lana.microposts.each do |post_following|
      assert michael.feed.include?(post_following)
    end
    # Posts from self
    michael.microposts.each do |post_self|
      assert michael.feed.include?(post_self)
    end
    # Posts from unfollowed user
    archer.microposts.each do |post_unfollowed|
      assert_not michael.feed.include?(post_unfollowed)
    end
  end

app/models/user.rb
  # Returns a user's status feed.
  def feed
    Micropost.where("user_id IN (?) OR user_id = ?", following_ids, id)
  end

  # Follows a user.
  def follow(other_user)
    active_relationships.create(followed_id: other_user.id)
  end

app/models/user.rb
  # Returns a user's status feed.
  def feed
    Micropost.where("user_id IN (:following_ids) OR user_id = :user_id",
                    following_ids: following_ids, user_id: id)
  end

app/models/user.rb
  # Returns a user's status feed.
  def feed
    following_ids = "SELECT followed_id FROM relationships
                     WHERE  follower_id = :user_id"
    Micropost.where("user_id IN (#{following_ids})
                     OR user_id = :user_id", user_id: id)
  end




shell terminal
$ rails test
$ git add -A
$ git commit -m "Add user following"
$ git checkout master
$ git merge following-users
$ git push

Github URL for sample_app project: https://github.com/jimmy2046/sample_app

  • I completed all 14 chapters on July 22, 2017.

All Completed: Michael Hartl's Ruby on Rails Tutorial (Part I)

sample_app: Chapter 14 Following users log

shell terminal
$ cd sample_app
$ rails s -b 0.0.0.0 -p 3000

Firefox: http://localhost:3000/

shell terminal
$ git checkout -b following-users


$ rails generate model Relationship follower_id:integer followed_id:integer

db/migrate/[timestamp]_create_relationships.rb
    add_index :relationships, :follower_id
    add_index :relationships, :followed_id
    add_index :relationships, [:follower_id, :followed_id], unique: true

$ rails db:migrate
== 20170722215137 CreateRelationships: migrating ==============================
-- create_table(:relationships)
   -> 0.0247s
-- add_index(:relationships, :follower_id)
   -> 0.0011s
-- add_index(:relationships, :followed_id)
   -> 0.0011s
-- add_index(:relationships, [:follower_id, :followed_id], {:unique=>true})
   -> 0.0016s
== 20170722215137 CreateRelationships: migrated (0.0288s) =====================

app/models/user.rb
  has_many :active_relationships, class_name:  "Relationship",
                                  foreign_key: "follower_id",
                                  dependent:   :destroy


app/models/relationship.rb
class Relationship < ApplicationRecord
  belongs_to :follower, class_name: "User"
  belongs_to :followed, class_name: "User"   
end

test/models/relationship_test.rb
require 'test_helper'

class RelationshipTest < ActiveSupport::TestCase

  def setup
    @relationship = Relationship.new(follower_id: users(:michael).id,
                                     followed_id: users(:archer).id)
  end

  test "should be valid" do
    assert @relationship.valid?
  end

  test "should require a follower_id" do
    @relationship.follower_id = nil
    assert_not @relationship.valid?
  end

  test "should require a followed_id" do
    @relationship.followed_id = nil
    assert_not @relationship.valid?
  end
end

app/models/relationship.rb
  validates :follower_id, presence: true
  validates :followed_id, presence: true

test/fixtures/relationships.yml
# empty

app/models/user.rb
  has_many :following, through: :active_relationships, source: :followed

test/models/user_test.rb
  test "should follow and unfollow a user" do
    michael = users(:michael)
    archer  = users(:archer)
    assert_not michael.following?(archer)
    michael.follow(archer)
    assert michael.following?(archer)
    michael.unfollow(archer)
    assert_not michael.following?(archer)
  end

app/models/user.rb
  # Follows a user.
  def follow(other_user)
    following << other_user
  end

  # Unfollows a user.
  def unfollow(other_user)
    following.delete(other_user)
  end

  # Returns true if the current user is following the other user.
  def following?(other_user)
    following.include?(other_user)
  end

app/models/user.rb
  has_many :microposts, dependent: :destroy
  has_many :active_relationships,  class_name:  "Relationship",
                                   foreign_key: "follower_id",
                                   dependent:   :destroy
  has_many :passive_relationships, class_name:  "Relationship",
                                   foreign_key: "followed_id",
                                   dependent:   :destroy
  has_many :following, through: :active_relationships,  source: :followed
  has_many :followers, through: :passive_relationships, source: :follower

test/models/user_test.rb
  test "should follow and unfollow a user" do
    assert archer.followers.include?(michael)
  end

db/seeds.rb
# Microposts
users = User.order(:created_at).take(6)
50.times do
  content = Faker::Lorem.sentence(5)
  users.each { |user| user.microposts.create!(content: content) }
end

# Following relationships
users = User.all
user  = users.first
following = users[2..50]
followers = users[3..40]
following.each { |followed| user.follow(followed) }
followers.each { |follower| follower.follow(user) }

shell terminal
$ rails db:migrate:reset
$ rails db:seed

config/routes.rb
Rails.application.routes.draw do
#  get 'password_resets/new'
#  get 'password_resets/edit'

  root 'static_pages#home'
  get  '/help',    to: 'static_pages#help'
  get  '/about',   to: 'static_pages#about'
  get  '/contact', to: 'static_pages#contact'
  get  '/signup',  to: 'users#new'
#  post '/signup',  to: 'users#create'   
  get    '/login',   to: 'sessions#new'
  post   '/login',   to: 'sessions#create'
  delete '/logout',  to: 'sessions#destroy'

  resources :users do
    member do
      get :following, :followers
    end
  end
       
  resources :account_activations, only: [:edit]
  resources :password_resets,     only: [:new, :create, :edit, :update]
  resources :microposts,          only: [:create, :destroy]   
end

app/views/shared/_stats.html.erb
<% @user ||= current_user %>
<div class="stats">
  <a href="<%= following_user_path(@user) %>">
    <strong id="following" class="stat">
      <%= @user.following.count %>
    </strong>
    following
  </a>
  <a href="<%= followers_user_path(@user) %>">
    <strong id="followers" class="stat">
      <%= @user.followers.count %>
    </strong>
    followers
  </a>
</div>

app/views/static_pages/home.html.erb
      <section class="stats">
        <%= render 'shared/stats' %>
      </section>

app/assets/stylesheets/custom.scss
.stats {
  overflow: auto;
  margin-top: 0;
  padding: 0;
  a {
    float: left;
    padding: 0 10px;
    border-left: 1px solid $gray-lighter;
    color: gray;
    &:first-child {
      padding-left: 0;
      border: 0;
    }
    &:hover {
      text-decoration: none;
      color: blue;
    }
  }
  strong {
    display: block;
  }
}

.user_avatars {
  overflow: auto;
  margin-top: 10px;
  .gravatar {
    margin: 1px 1px;
  }
  a {
    padding: 0;
  }
}

.users.follow {
  padding: 0;
}

Firefox: http://localhost:3000/


config/routes.rb
  resources :relationships,       only: [:create, :destroy]

app/views/users/show.html.erb
<% provide(:title, @user.name) %>
<div class="row">
  <aside class="col-md-4">
    <section class="user_info">       
      <h1>
        <%= gravatar_for @user %>
        <%= @user.name %>
      </h1>
    </section>
    <section class="stats">
      <%= render 'shared/stats' %>
    </section>     
  </aside>
  <div class="col-md-8">
    <%= render 'follow_form' if logged_in? %>     
    <% if @user.microposts.any? %>
      <h3>Microposts (<%= @user.microposts.count %>)</h3>
      <ol class="microposts">
        <%= render @microposts %>
      </ol>
      <%= will_paginate @microposts %>
    <% end %>
  </div>   
</div>


Firefox: http://localhost:3000/users/2


Firefox: http://localhost:3000/users/6


test/controllers/users_controller_test.rb
  test "should redirect following when not logged in" do
    get following_user_path(@user)
    assert_redirected_to login_url
  end

  test "should redirect followers when not logged in" do
    get followers_user_path(@user)
    assert_redirected_to login_url
  end


app/controllers/users_controller.rb
  before_action :logged_in_user, only: [:index, :edit, :update, :destroy,
                                        :following, :followers]

  def following
    @title = "Following"
    @user  = User.find(params[:id])
    @users = @user.following.paginate(page: params[:page])
    render 'show_follow'
  end

  def followers
    @title = "Followers"
    @user  = User.find(params[:id])
    @users = @user.followers.paginate(page: params[:page])
    render 'show_follow'
  end

Firefox: http://localhost:3000/users/1/following

Firefox: http://localhost:3000/users/1/followers

Friday, July 21, 2017

Completed Ch. 13: User microposts (Part 2)

sample app: Completed Ch. 13: User microposts (Part 2)

app/views/static_pages/home.html.erb
<% if logged_in? %>
  <div class="row">
    <aside class="col-md-4">
      <section class="user_info">
        <%= render 'shared/user_info' %>
      </section>
      <section class="micropost_form">
        <%= render 'shared/micropost_form' %>
      </section>
    </aside>
  </div>
<% else %>
<div class="center jumbotron">
  <h1>Welcome to the Sample App</h1>

  <h2>
    This is the home page for the
    <a href="http://www.railstutorial.org/">Ruby on Rails Tutorial</a>
    sample application.
  </h2>

  <%= link_to "Sign up now!", signup_path, class: "btn btn-lg btn-primary" %>
</div>

<%= link_to image_tag("rails.png", alt: "Rails logo"),
            'http://rubyonrails.org/' %>
<% end %>

app/views/shared/_user_info.html.erb
<%= link_to gravatar_for(current_user, size: 50), current_user %>
<h1><%= current_user.name %></h1>
<span><%= link_to "view my profile", current_user %></span>
<span><%= pluralize(current_user.microposts.count, "micropost") %></span>

app/views/shared/_micropost_form.html.erb
<%= form_for(@micropost) do |f| %>
  <%= render 'shared/error_messages', object: f.object %>
  <div class="field">
    <%= f.text_area :content, placeholder: "Compose new micropost..." %>
  </div>
  <%= f.submit "Post", class: "btn btn-primary" %>
<% end %>

app/controllers/static_pages_controller.rb
  def home
    @micropost = current_user.microposts.build if logged_in?
  end

app/views/shared/_error_messages.html.erb
<% if @user.errors.any? %>
  <div id="error_explanation">
    <div class="alert alert-danger">
      The form contains <%= pluralize(@user.errors.count, "error") %>.
    </div>
    <ul>
    <% @user.errors.full_messages.each do |msg| %>
      <li><%= msg %></li>
    <% end %>
    </ul>
  </div>
<% end %>

app/views/users/new.html.erb
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>

<div class="row">
  <div class="col-md-6 col-md-offset-3">
     
    <%= form_for(@user) do |f| %>
      <%= render 'shared/error_messages', object: f.object %>

      <%= f.label :name %>
      <%= f.text_field :name, class: 'form-control' %>
     
      <%= f.label :email %>
      <%= f.email_field :email, class: 'form-control' %>

      <%= f.label :password %>
      <%= f.password_field :password, class: 'form-control' %>

      <%= f.label :password_confirmation, "Confirmation" %>
      <%= f.password_field :password_confirmation, class: 'form-control' %>

      <%= f.submit "Create my account", class: "btn btn-primary" %>
    <% end %>
  </div>
</div>

app/views/users/edit.html.erb
      <%= render 'shared/error_messages', object: f.object %>

app/views/password_resets/edit.html.erb
      <%= render 'shared/error_messages', object: f.object %>

app/views/shared/_error_message.html.erb
<% if object.errors.any? %>
  <div id="error_explanation">
    <div class="alert alert-danger">
      The form contains <%= pluralize(object.errors.count, "error") %>.
    </div>
    <ul>
    <% object.errors.full_messages.each do |msg| %>
      <li><%= msg %></li>
    <% end %>
    </ul>
  </div>
<% end %>

app/models/user.rb
  def feed
    Micropost.where("user_id = ?", id)
  end

app/controllers/static_pages_controller.rb
  def home
    if logged_in?
      @micropost  = current_user.microposts.build
      @feed_items = current_user.feed.paginate(page: params[:page])
    end
  end

app/views/shared/_feed.html.erb
<% if @feed_items.any? %>
  <ol class="microposts">
    <%= render @feed_items %>
  </ol>
  <%= will_paginate @feed_items %>
<% end %>

app/views/static_pages/home.html.erb
<% if logged_in? %>
  <div class="row">
    <aside class="col-md-4">
      <section class="user_info">
        <%= render 'shared/user_info' %>
      </section>
      <section class="micropost_form">
        <%= render 'shared/micropost_form' %>
      </section>
    </aside>
    <div class="col-md-8">
      <h3>Micropost Feed</h3>
      <%= render 'shared/feed' %>
    </div>         
  </div>
<% else %>
<div class="center jumbotron">
  <h1>Welcome to the Sample App</h1>

  <h2>
    This is the home page for the
    <a href="http://www.railstutorial.org/">Ruby on Rails Tutorial</a>
    sample application.
  </h2>

  <%= link_to "Sign up now!", signup_path, class: "btn btn-lg btn-primary" %>
</div>

<%= link_to image_tag("rails.png", alt: "Rails logo"),
            'http://rubyonrails.org/' %>
<% end %>



app/controllers/microposts_controller.rb
    else
      @feed_items = []

app/views/microposts/_micropost.html.erb
<%= link_to "delete", micropost, method: :delete,
data: { confirm: "You sure?" } %>

test/fixtures/microposts.yml
ants:
  content: "Oh, is that what you want? Because that's how you get ants!"
  created_at: <%= 2.years.ago %>
  user: archer

zone:
  content: "Danger zone!"
  created_at: <%= 3.days.ago %>
  user: archer

tone:
  content: "I'm sorry. Your words made sense, but your sarcastic tone did not."
  created_at: <%= 10.minutes.ago %>
  user: lana

van:
  content: "Dude, this van's, like, rolling probable cause."
  created_at: <%= 4.hours.ago %>
  user: lana

test/controllers/microposts_controller_test.rb
  test "should redirect destroy for wrong micropost" do
    log_in_as(users(:michael))
    micropost = microposts(:ants)
    assert_no_difference 'Micropost.count' do
      delete micropost_path(micropost)
    end
    assert_redirected_to root_url
  end

$ rails generate integration_test microposts_interface

test/integration/microposts_interface_test.rb
require 'test_helper'

class MicropostsInterfaceTest < ActionDispatch::IntegrationTest

  def setup
    @user = users(:michael)
  end

  test "micropost interface" do
    log_in_as(@user)
    get root_path
    assert_select 'div.pagination'
    # Invalid submission
    assert_no_difference 'Micropost.count' do
      post microposts_path, params: { micropost: { content: "" } }
    end
    assert_select 'div#error_explanation'
    # Valid submission
    content = "This micropost really ties the room together"
    assert_difference 'Micropost.count', 1 do
      post microposts_path, params: { micropost: { content: content } }
    end
    assert_redirected_to root_url
    follow_redirect!
    assert_match content, response.body
    # Delete post
    assert_select 'a', text: 'delete'
    first_micropost = @user.microposts.paginate(page: 1).first
    assert_difference 'Micropost.count', -1 do
      delete micropost_path(first_micropost)
    end
    # Visit different user (no delete links)
    get user_path(users(:archer))
    assert_select 'a', text: 'delete', count: 0
  end   
   
end

Gemfile
gem 'carrierwave',             '1.1.0'
gem 'mini_magick',             '4.7.0'
gem 'fog',                     '1.40.0'

$ bundle install
$ rails generate uploader Picture
$ rails generate migration add_picture_to_microposts picture:string
$ rails db:migrate

app/models/micropost.rb
  mount_uploader :picture, PictureUploader

Ctrl + C
$ rails s -b 0.0.0.0 -p 3000

app/views/shared/_micropost_form.html.erb
  <span class="picture">
    <%= f.file_field :picture %>
  </span>

app/controllers/microposts_controller.rb
    def micropost_params
      params.require(:micropost).permit(:content, :picture)
    end

app/views/microposts/_micropost.html.erb
    <%= image_tag micropost.picture.url if micropost.picture? %>


app/uploaders/picture_uploader.rb
  # Add a white list of extensions which are allowed to be uploaded.
  def extension_white_list
    %w(jpg jpeg gif png)
  end

app/models/micropost.rb
  validate  :picture_size

  private

    # Validates the size of an uploaded picture.
    def picture_size
      if picture.size > 5.megabytes
        errors.add(:picture, "should be less than 5MB")
      end
    end

app/views/shared/_micropost_form.html.erb
<%= form_for(@micropost) do |f| %>
  <%= render 'shared/error_messages', object: f.object %>
  <div class="field">
    <%= f.text_area :content, placeholder: "Compose new micropost..." %>
  </div>
  <%= f.submit "Post", class: "btn btn-primary" %>
  <span class="picture">
    <%= f.file_field :picture, accept: 'image/jpeg,image/gif,image/png' %>
  </span>
<% end %>

<script type="text/javascript">
  $('#micropost_picture').bind('change', function() {
    var size_in_megabytes = this.files[0].size/1024/1024;
    if (size_in_megabytes > 5) {
      alert('Maximum file size is 5MB. Please choose a smaller file.');
    }
  });
</script>

$ sudo apt-get update
$ sudo apt-get install imagemagick --fix-missing

app/uploaders/picture_uploader.rb
class PictureUploader < CarrierWave::Uploader::Base
   include CarrierWave::MiniMagick
   process resize_to_limit: [400, 400]

  storage :file

  def store_dir
    "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
  end

   def extension_whitelist
     %w(jpg jpeg gif png)
   end

end


app/uploaders/picture_uploader.rb
  if Rails.env.production?
    storage :fog
  else
    storage :file
  end
shell terminal:
$ rails test
$ git add -A
$ git commit -m "Add user microposts"
$ git checkout master
$ git merge user-microposts
$ git push

The URL address of the sample_app project was: https://github.com/jimmy2046/sample_app

Completed Ch. 13: User microposts (Part 1)

sample_app: Chapter 13 User microposts log

$ cd sample_app
$ rails s -b 0.0.0.0 -p 3000

Firefox: http://localhost:3000/

$ git checkout -b user-microposts


$ rails generate model Micropost content:text user:references

db/migrate/
    add_index :microposts, [:user_id, :created_at]

test/models/micropost_test.rbrequire 'test_helper'
class MicropostTest < ActiveSupport::TestCase

  def setup
    @user = users(:michael)
    # This code is not idiomatically correct.
    @micropost = Micropost.new(content: "Lorem ipsum", user_id: @user.id)
  end

  test "should be valid" do
    assert @micropost.valid?
  end

  test "user id should be present" do
    @micropost.user_id = nil
    assert_not @micropost.valid?
  end
end

app/models/micropost.rb
  validates :user_id, presence: true

test/models/micropost_test.rb
  test "content should be present" do
    @micropost.content = "   "
    assert_not @micropost.valid?
  end

  test "content should be at most 140 characters" do
    @micropost.content = "a" * 141
    assert_not @micropost.valid?
  end

app/models/micropost.rb
  validates :content, presence: true, length: { maximum: 140 }

app/models/user.rb
  has_many :microposts

test/models/micropost_test.rb
  def setup
    @user = users(:michael)
    @micropost = @user.microposts.build(content: "Lorem ipsum")
  end

test/models/micropost_test.rb
  test "order should be most recent first" do
    assert_equal microposts(:most_recent), Micropost.first
  end

test/fixtures/microposts.yml
orange:
  content: "I just ate an orange!"
  created_at: <%= 10.minutes.ago %>

tau_manifesto:
  content: "Check out the @tauday site by @mhartl: http://tauday.com"
  created_at: <%= 3.years.ago %>

cat_video:
  content: "Sad cats are sad: http://youtu.be/PKffm2uI4dk"
  created_at: <%= 2.hours.ago %>

most_recent:
  content: "Writing a short test"
  created_at: <%= Time.zone.now %>

app/models/micropost.rb
  default_scope -> { order(created_at: :desc) }

test/models/user_test.rb
  test "associated microposts should be destroyed" do
    @user.save
    @user.microposts.create!(content: "Lorem ipsum")
    assert_difference 'Micropost.count', -1 do
      @user.destroy
    end
  end

app/models/user.rb
  has_many :microposts, dependent: :destroy

$ rails db:migrate:reset
$ rails db:seed
$ rails generate controller Microposts

app/views/microposts/_micropost.html.erb
<li id="micropost-<%= micropost.id %>">
  <%= link_to gravatar_for(micropost.user, size: 50), micropost.user %>
  <span class="user"><%= link_to micropost.user.name, micropost.user %></span>
  <span class="content"><%= micropost.content %></span>
  <span class="timestamp">
    Posted <%= time_ago_in_words(micropost.created_at) %> ago.
  </span>
</li>

app/controllers/users_controller.rb
  def show
    @user = User.find(params[:id])
    redirect_to root_url and return unless @user.activated?     
    @microposts = @user.microposts.paginate(page: params[:page])
  end

app/views/users/show.html.erb
  <div class="col-md-8">
    <% if @user.microposts.any? %>
      <h3>Microposts (<%= @user.microposts.count %>)</h3>
      <ol class="microposts">
        <%= render @microposts %>
      </ol>
      <%= will_paginate @microposts %>
    <% end %>
  </div>

db/seeds.rb
users = User.order(:created_at).take(6)
50.times do
  content = Faker::Lorem.sentence(5)
  users.each { |user| user.microposts.create!(content: content) }
end

$ rails db:migrate:reset
$ rails db:seed

Keyboard: Ctrl + C
$ rails s -b 0.0.0.0 -p 3000

app/assets/stylesheets/custom.scss
/* microposts */

.microposts {
  list-style: none;
  padding: 0;
  li {
    padding: 10px 0;
    border-top: 1px solid #e8e8e8;
  }
  .user {
    margin-top: 5em;
    padding-top: 0;
  }
  .content {
    display: block;
    margin-left: 60px;
    img {
      display: block;
      padding: 5px 0;
    }
  }
  .timestamp {
    color: $gray-light;
    display: block;
    margin-left: 60px;
  }
  .gravatar {
    float: left;
    margin-right: 10px;
    margin-top: 5px;
  }
}

aside {
  textarea {
    height: 100px;
    margin-bottom: 5px;
  }
}

span.picture {
  margin-top: 10px;
  input {
    border: 0;
  }
}

The microposts of page 2 of user no#1, that was generated by db.Seed, was: http://localhost:3000/users/1?page=2



$ rails generate integration_test users_profile

test/fixtures/microposts.yml
orange:
  content: "I just ate an orange!"
  created_at: <%= 10.minutes.ago %>
  user: michael 

tau_manifesto:
  content: "Check out the @tauday site by @mhartl: http://tauday.com"
  created_at: <%= 3.years.ago %>
  user: michael

cat_video:
  content: "Sad cats are sad: http://youtu.be/PKffm2uI4dk"
  created_at: <%= 2.hours.ago %>
  user: michael

most_recent:
  content: "Writing a short test"
  created_at: <%= Time.zone.now %>
  user: michael
 
<% 30.times do |n| %>
micropost_<%= n %>:
  content: <%= Faker::Lorem.sentence(5) %>
  created_at: <%= 42.days.ago %>
  user: michael
<% end %>

test/integration/users_profile_test.rb
require 'test_helper'

class UsersProfileTest < ActionDispatch::IntegrationTest
  include ApplicationHelper

  def setup
    @user = users(:michael)
  end

  test "profile display" do
    get user_path(@user)
    assert_template 'users/show'
    assert_select 'title', full_title(@user.name)
    assert_select 'h1', text: @user.name
    assert_select 'h1>img.gravatar'
    assert_match @user.microposts.count.to_s, response.body
    assert_select 'div.pagination'
    @user.microposts.paginate(page: 1).each do |micropost|
      assert_match micropost.content, response.body
    end
  end   

end

app/controllers/users_controller.rb
  before_action :logged_in_user, only: [:index, :edit, :update, :destroy]

config/routes.rb
  resources :microposts,          only: [:create, :destroy]

test/controllers/microposts_controller_test.rb
require 'test_helper'

class MicropostsControllerTest < ActionDispatch::IntegrationTest

  def setup
    @micropost = microposts(:orange)
  end

  test "should redirect create when not logged in" do
    assert_no_difference 'Micropost.count' do
      post microposts_path, params: { micropost: { content: "Lorem ipsum" } }
    end
    assert_redirected_to login_url
  end

  test "should redirect destroy when not logged in" do
    assert_no_difference 'Micropost.count' do
      delete micropost_path(@micropost)
    end
    assert_redirected_to login_url
  end
end

app/controllers/application_controller.rb
  private

    # Confirms a logged-in user.
    def logged_in_user
      unless logged_in?
        store_location
        flash[:danger] = "Please log in."
        redirect_to login_url
      end
    end

app/controllers/users_controller.rb
DELETED action def logged_in_user

app/controllers/microposts_controller.rb
class MicropostsController < ApplicationController
  before_action :logged_in_user, only: [:create, :destroy]

  def create
  end

  def destroy
  end   

end

app/controllers/microposts_controller.rb
class MicropostsController < ApplicationController
  before_action :logged_in_user, only: [:create, :destroy]

  def create
    @micropost = current_user.microposts.build(micropost_params)
    if @micropost.save
      flash[:success] = "Micropost created!"
      redirect_to root_url
    else
      render 'static_pages/home'
    end
  end   

  def destroy
  end   

  private

    def micropost_params
      params.require(:micropost).permit(:content)
    end   
   
end

How to kill an abandoned process in Linux/Unix

I remembered it, then I forgot, then I remembered it, and then I forgot again. In case of a Linux/Unit process hang, I have to figure out ...