Wednesday, August 23, 2017

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 the PID of the stalled process and then use the kill command to close it.
  • To figure out the PID of the stalled process, in shell terminal type:
ps -u [username]

  • Then, use your own justification to figure out the PID. To kill a process with specific PID:
kill -9 [PID]

References:

How to see process created by specific user in Unix/linux
http://unix.stackexchange.com/questions/85466/how-to-see-process-created-by-specific-user-in-unix-linux

The kill Command
http://www.linfo.org/kill.html

Tuesday, August 15, 2017

Switching from SQLite to PostgreSQL in Development Environment

I don't understand why Ruby on Rails Tutorial uses SQLite database for development and uses PostgreSQL database in Heroku for production.
Why don't they use PostgreSQL for all the environments? To use PostgreSQL in development environment, it is as simple as just adding the "-d postgresql" parameter when creating a new Rails project.
$ rails new myapp -d postgresql

I am writing this because when I was going further after the Rails Tutorial, I just wanted to add Comments and Articles models for a message board, some of the database migration codes that worked well in Sqlite but they do not work in Heroku's PostgreSQL.
For example, in db/migrate/20170812232746_add_user_ref_to_articles.rb
# This line works in Sqlite development enviroment
# This line does not work in Heroku's PostgreSQL production environment
add_index :articles, [:user_id, :created_at]   

So, I decided to switch from Sqlite database to PostgreSQL database in my Linux development environment. Approximately, this was what I did for the switching of the database.

In project: myapp_postgres


* I created a new Rails project that uses PostgreSQL:
$ cd ror
$ rails new myapp_postgres -d postgresql

* I made sure that I could create the PostgreSQL database and started the Rails server.
$ cd myapp_postgres
$ rake db:create
$ rails s -b 0.0.0.0 -p 3000

* I went "Turbo Speed" for the Chapter 2 of Rails Tutorial. I did NOT change the Gemfile of myapp_postgres project. And I did NOT change database.yml.

* I initialized a local Git repository, added all files, committed the changes, added remote Github URL, and pushed it onto Github.
$ git init
$ git add -A
$ git commit -m "Initialize repository"
$ git remote add origin https://github.com/jimmy2046/myapp_postgres.git
$ git push -u origin --all
* I created the "hello" action, committed the changes, created an Heroku project and pushed it onto Heroku.
$ git commit -am "Add hello"
$ heroku create
$ git push heroku master

* I generated the scaffold for User and made sure the database migration command worked.
$ rails generate scaffold User name:string email:string
$ rails db:migrate
* I generated the scaffold for Micropost.
$ rails generate scaffold Micropost content:text user_id:integer
$ rails db:migrate
* Using Firefox, I tried to add a new user and added a new micropost in order to make sure the local PostgreSQL database was working properly in development environment.

* At the end of Chapter 2, I added all untracked files, committed the changes, and pushed project myapp_postgres onto Github.
$ git add -A
$ git commit -m "Finish toy app"
$ git push

* At the same time, I pushed myapp_postgres to Heroku and ran database migration for Heroku production.
$ git push heroku
$ heroku run rails db:migrate

* At that time, I had a new PostgreSQL database project called myapp_postgres with configurations and settings for Heroku PostgreSQL deployment.

In project: myapp2

* After that, I went back to myapp2 project. I changed the the directory myapp2 and checked out a new branch called: "attempt-switch-to-postgresql".
$ cd ~/myapp2
$ git checkout -b  attempt-switch-to-postgresql

* In myapp2, I made a backup copy of the database.yml file. And then, I copied and pasted the database.yml file, that I got from myapp_postgres using "$ rails new myapp_postgres -d postgresql" to myapp2.
myapp2/config/database.yml
# PostgreSQL. Versions 9.1 and up are supported.
#
# Install the pg driver:
#   gem install pg
# On OS X with Homebrew:
#   gem install pg -- --with-pg-config=/usr/local/bin/pg_config
# On OS X with MacPorts:
#   gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config
# On Windows:
#   gem install pg
#       Choose the win32 build.
#       Install PostgreSQL and put its /bin directory on your path.
#
# Configure Using Gemfile
# gem 'pg'
#
default: &default
  adapter: postgresql
  encoding: unicode
  # For details on connection pooling, see Rails configuration guide
  # http://guides.rubyonrails.org/configuring.html#database-pooling
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

development:
  <<: *default
  database: myapp_postgres_development

  # The specified database role being used to connect to postgres.
  # To create additional roles in postgres see `$ createuser --help`.
  # When left blank, postgres will use the default role. This is
  # the same name as the operating system user that initialized the database.
  #username: myapp_postgres

  # The password associated with the postgres role (username).
  #password:

  # Connect on a TCP socket. Omitted by default since the client uses a
  # domain socket that doesn't need configuration. Windows does not have
  # domain sockets, so uncomment these lines.
  #host: localhost

  # The TCP port the server listens on. Defaults to 5432.
  # If your server runs on a different port number, change accordingly.
  #port: 5432

  # Schema search path. The server defaults to $user,public
  #schema_search_path: myapp,sharedapp,public

  # Minimum log levels, in increasing order:
  #   debug5, debug4, debug3, debug2, debug1,
  #   log, notice, warning, error, fatal, and panic
  # Defaults to warning.
  #min_messages: notice

# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  <<: *default
  database: myapp_postgres_test

# As with config/secrets.yml, you never want to store sensitive information,
# like your database password, in your source code. If your source code is
# ever seen by anyone, they now have access to your database.
#
# Instead, provide the password as a unix environment variable when you boot
# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database
# for a full rundown on how to provide these environment variables in a
# production deployment.
#
# On Heroku and other platform providers, you may have a full connection URL
# available as an environment variable. For example:
#
#   DATABASE_URL="postgres://myuser:mypass@localhost/somedatabase"
#
# You can use this database configuration with:
#
#   production:
#     url: <%= ENV['DATABASE_URL'] %>
#
production:
  <<: *default
  database: myapp_postgres_production
  username: myapp_postgres
  password: <%= ENV['MYAPP_POSTGRES_DATABASE_PASSWORD'] %>

* In Gemfile, I put gem 'pg', '0.18.4' on the top section. That meant Rails would use PostgreSQL for all Development, Testing and Production environments. I put a remark comment for gem 'sqlite3', '1.3.13' in development group, and I commented out the gem 'pg', '0.18.4' in Production group.
myapp2/Gemfile
source 'https://rubygems.org'

gem 'rails',        '5.1.2'
gem 'bcrypt',         '3.1.11'
gem 'faker',          '1.7.3'
gem 'carrierwave',             '1.1.0'
gem 'mini_magick',             '4.7.0'
gem 'fog',                     '1.40.0'
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'

gem 'pg', '0.18.4'

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]

* Then, I ran bundle update.
$ bundle update

* And the, I restarted the my local Rails server.
Ctrl + C
$ rails s -b 0.0.0.0 -p 3000

* In local Linux development environment, I attempted to drop the database, created a new one. But, I was stuck during database migration.
$ rake db:drop db:create db:migrate

* It took me some time for my debug skill. Afterwards, I figured out that the add_index for user_id code worked well in Sqlite but not in PostgreSQL. So, I commented out the add_index line for model Articles and model Comments.
myapp2/db/migrate/20170812232746_add_user_ref_to_articles.rb
class AddUserRefToArticles < ActiveRecord::Migration[5.1]
  def change
    add_reference :articles, :user, foreign_key: true
  end
   
#    add_index :articles, [:user_id, :created_at]   
end
Similarly,
myapp2/db/migrate/20170814052759_add_user_to_comments.rb
class AddUserToComments < ActiveRecord::Migration[5.1]
  def change
    add_reference :comments, :user, foreign_key: true
  end
#    add_index :comments, [:user_id, :created_at]   
end

* After I had commented out the add_index to the database, I ran database migration again. The migration was successful.
$ rails db:migrate

* Then, I seeded the database.
$ rails db:seed

* Then, I deleted the old Sqlite database file in myapp2/db directory.
myapp2/db
deleted: test.sqlite3
deleted: development.sqlite3

* Finally, I pushed the changes to Github and deployed to Heroku.
$ rails test
$ git add -A
$ git commit -m "Changed to PostgreSQL in Development Env"
$ git checkout master
$ git merge attempt-switch-to-postgresql
$ git push

$ git push heroku
$ heroku pg:reset DATABASE
$ heroku run rails db:migrate
$ heroku run rails db:seed

* My Gihub URL is: https://github.com/jimmy2046/myapp2/commit/8a00ad4b549feb43cc832727c4701f6291e48334

* My Heroku URL is: https://vast-mesa-46380.herokuapp.com/articles?class=nav-link

Reference websites:

How to change your Rails app database from SQLite to PostgreSQL before deploying to Heroku
https://medium.com/@helenflam/how-to-change-your-rails-app-database-from-sqlite-to-postgresql-before-deploying-to-heroku-ae2acc25c7ac

Change from SQLite to PostgreSQL in a fresh Rails project
https://stackoverflow.com/questions/6710654/change-from-sqlite-to-postgresql-in-a-fresh-rails-project

Installing PostgreSQL database for Ruby on Rails on Ubuntu Linux

I realized that I did not write a blog for the installation procedures of PostgreSQL database for Ruby on Rails on Ubuntu Linux. This is an excerpt from GoRails.com :

Setting Up PostgreSQL

For PostgreSQL, we're going to add a new repository to easily install a recent version of Postgres.
sudo sh -c "echo 'deb http://apt.postgresql.org/pub/repos/apt/ xenial-pgdg main' > /etc/apt/sources.list.d/pgdg.list"
wget --quiet -O - http://apt.postgresql.org/pub/repos/apt/ACCC4CF8.asc | sudo apt-key add -
sudo apt-get update
sudo apt-get install postgresql-common
sudo apt-get install postgresql-9.5 libpq-dev

The postgres installation doesn't setup a user for you, so you'll need to follow these steps to create a user with permission to create databases. Feel free to replace chris with your username.
sudo -u postgres createuser chris -s

# If you would like to set a password for the user, you can do the following
sudo -u postgres psql
postgres=# \password chris

Creating Ruby on Rails application

#### If you want to use Postgres
# Note that this will expect a postgres user with the same username
# as your app, you may need to edit config/database.yml to match the
# user you created earlier

rails new myapp -d postgresql

Author's note: I did not modify the 'database.yml' file. I just left it as it the original from the 'rails new' command.

# Move into the application directory
cd myapp

# If you setup MySQL or Postgres with a username/password, modify the
# config/database.yml file to contain the username/password that you specified

# Create the database
rake db:create

rails server

You can now visit http://localhost:3000 to view your new website!

Reference:

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

Thursday, August 10, 2017

Linux: Increasing Increasing the amount of inotify watchers

Today, I wanted to add Article and Comment for my Ruby on Rails myapp2 project. It is based on Getting Started with Rails online tutorial (http://guides.rubyonrails.org/getting_started.html).

When I typed Rails generate controller command, something weird was shown on the screen:
jimmyc@Jimmy-C-2017:~/myapp2$ rails generate controller Articles
FATAL: Listen error: unable to monitor directories for changes.
Visit https://github.com/guard/listen/wiki/Increasing-the-amount-of-inotify-watchers for info on how to fix this.

Then, I searched on Google: "FATAL: Listen error: unable to monitor directories for changes". The search result showed a Stack Overflow article. I also surfed the Github article that was shown on Linux terminal.

I tried to type this command in shell terminal and hopefully it could get through:
$ echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p

my shell terminal:
jimmyc@Jimmy-C-2017:~/myapp2$ echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p
[sudo] password for jimmyc:
fs.inotify.max_user_watches=524288
fs.inotify.max_user_watches = 524288

Good, this time the Rails Generate Controller command was successful.
jimmyc@Jimmy-C-2017:~/myapp2$ rails generate controller Articles
Running via Spring preloader in process 3769
      create  app/controllers/articles_controller.rb
      invoke  erb
      create    app/views/articles
      invoke  test_unit
      create    test/controllers/articles_controller_test.rb
      invoke  helper
      create    app/helpers/articles_helper.rb
      invoke    test_unit
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/articles.coffee
      invoke    scss
      create      app/assets/stylesheets/articles.scss

Reference:
Increasing the amount of inotify watchers
https://github.com/guard/listen/wiki/Increasing-the-amount-of-inotify-watchers

Listen error: unable to monitor directories for changes
https://stackoverflow.com/questions/42225677/listen-error-unable-to-monitor-directories-for-changes

Tuesday, August 8, 2017

Linking a CSS file on a sub-directory of a parent directory in HTML

Sometimes, for a better organized file system of a web design, I need to create some sub-directories and put those files that belonged to the same category into the same directory.

For example, this is the file structure of my HTML website:
+--- html_publish/
|   +--- images/
|        pic01-IMG_0584.JPG
|        pic02-IMG_0585.JPG
|
|   +--- photo01/
|        detail01.html
|        detail02.html
|
|   +--- saturn/
|       +--- css/
|            custom.css
|
|   +--- templated-radius/
|       +--- css/
|            main.css
|
|   index.html
|   photo01.html
|
  
The file details01.html is located under the subdirectory photo01

In Linux shell terminal, the path is:
~/html_publish/photo01/details01.html

If I want to link the CSS style that located in
~/html_publish/templated-radius/css/main.css. 

To link the CSS file (main.css) from detail01.html, I need to go up to one parent directory (html_publish), and then go down to templated-radius sub-directory and then go down to css sub-directory. In the details01.html file:
~/html_publish/photo01/details01.html
<link rel="stylesheet" href="../templated-radius/css/main.css" />

The "two dots" (../) means go up one directory. In some circumstances, if I want to go up 2 levels of directory I can do (../../).

Similarly, I want to link an image file that is located under the sub-directory images of the parent directory.
Images file:
~/html_publish/images/pic01-IMG_0584.JPG

And the HTML file detail01.html is located under the photo01 sub-directory.
HTML file:
~/html_publish/photo01/details01.html

If I want to link the image file, for the <img> tag in details01.html:
~/html_publish/photo01/details01.html
<img src="../images/pic01-IMG_0584.JPG" alt="" />

Reference:
How do I actually link a CSS stylesheet to a HTML sheet?
https://www.codecademy.com/en/forum_questions/553bcfc6d3292f7e1b000760

Saturday, August 5, 2017

Suitable Image Pixel Size for Blogging

It is a common sense that any picture taken from iPhone and Android phone needs to be re-sized before it is good to post on a blog.

But, there is no standardized way to shrink an image. In Photoshop, I used to use the "Resize image" command to shrink an image. I maintained the aspect ratio and I shrank the image to certain percentage by "trial-and-error" or "guessing".

I just found a magic number on a website: 690 pixels. I do not understand why 690 pixels, but it works very good at least for my blog page: (https://jimmy2046.github.io/photo01.html)

For example, in Linux Pinta image editor, if the original size of one side of an image is 1800 pixels.
  • I click the Image -> Resize Image menu
  • In Resize Image window, click the by Absolute Size button
  • Make sure the "Maintain aspect ratio" option is checked on
  • (For me), on the longer side, I type 690 pixels. Notice that another size will also be shrunk automatically
  • Click OK button. Now the image is good for online HTML blog posting


Reference:
10 Tips on Best Image Size for Your Blog
http://www.1dogwoof.com/10-tips-best-image-size-blog/

Thursday, August 3, 2017

Using Github Pages to host HTML CSS and Javascript website

I did not know that GitHub offers GitHub Pages that allow members to host a website directly from their GitHub repository. Each member can get one site per GitHub account.

The procedures to host a website using GitHub Pages on Ubuntu Linux:
  • Create a repository. Head over to GitHub and create a new repository named username.github.io, where username is your username (or organization name) on GitHub. If the first part of the repository doesn’t exactly match your username, it won’t work, so make sure to get it right.
  • On my Linux computer, create a directory. For example, html_publish and copy all the HTML, CSS and Javascript of the website file into that directory. My directory structure is:
+--- html_publish/
|    /about.html
|    /blog.html
|    /contact.html
|    /index.html
|    /README.md
|    /services.html
|   +--- css/
|        /bootstrap.min.css
|        /magnific-popup.css
|        /templatemo-style.css
|   +--- font-awesome-4.5.0/
|        /HELP-US-OUT.txt
|       +--- css/
|            /font-awesome.min.css
|       +--- fonts/
|            /FontAwesome.otf
|            /fontawesome-webfont.eot
|            /fontawesome-webfont.svg
|            /fontawesome-webfont.ttf
|            /fontawesome-webfont.woff
|            /fontawesome-webfont.woff2
|   +--- img/
|        /img-11-01.jpg
|        /img-11-02.jpg
|        /img-11-03.jpg
|        /img-11-04.jpg
|        /img-11-05.jpg
|        /img-11-06.jpg
|        /img-11-07.jpg
|        /img-11-08.jpg
|        /img-21-01.jpg
|        /img-21-01.jpg
|        /img-21-02.jpg
|        /img-21-03.jpg
|        /img-21-04.jpg
|        /img-21-05.jpg
|        /img-21-06.jpg
|        /logo-bg.jpg
|   +--- js/
|        /bootstrap.min.js
|        /jquery-1.11.3.min.js
|        /jquery.magnific-popup.min.js

  • Then, I used Linux shell terminal to create a README.md file, initialized a Git repository, added all untracked files, committed the changes, set remote GitHub push fetch URL locations, and pushed the files to GitHub. This is what I did:
cd html_publish

echo "# jimmy2046.github.io" >> README.md
git init
git add README.md
git commit -m "first commit"

git add -A
git commit -m "added all html css images javascript files"

git remote add origin https://github.com/jimmy2046/jimmy2046.github.io.git
git push -u origin master

  • This is a more reader friendly version of Git shell commands. Please replace username with your GitHub username.
cd html_publish

echo "# username.github.io" >> README.md
git init
git add README.md
git commit -m "first commit"

git add -A
git commit -m "added all html css images javascript files"

git remote add origin https://github.com/username/username.github.io.git
git push -u origin master


 
  • GitHub Pages support all functionalities of CSS and Javascript. It allows me to have total freedom and flexibility of website design.  The speed of the GitHub server is extremely fast. Fantastic.

References:
GitHub Pages | Websites for you and your projects, hosted directly from your GitHub repository. Just edit, push, and your changes are live.
https://pages.github.com/

Finally, a Guide to Hosting Your Website
https://www.jonhmchan.com/blog/2014/4/28/finally-a-guide-to-hosting-your-website

Author's GitHub Pages (under construction)
https://jimmy2046.github.io/index.html

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

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 ...