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/
Monday, July 31, 2017
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
After I had installed Heroku, I needed to log in and add my public SSH key.
shell terminal
Reference:
Heroku CLI | Heroku Dev Center - Debian/Ubuntu
https://devcenter.heroku.com/articles/heroku-cli#debian-ubuntu
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
Download the Heroku CLI for Debian/Ubuntu
# Run this from your terminal.shell 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
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
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
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:
I thought that my Dell laptop could support the 64-bit version but it couldn't. During the installation, the system prompted:
Ubuntu did not put the 32-bit version conspicuously, I found the 32-bit version by search something like this on Google:
As I read the webpage, http://releases.ubuntu.com/16.04/, it states that:
32-bit PC (i386) desktop image
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:
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
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
sample_app_heroku_2/config/environments/production.rb
sample_app_heroku_2/config/puma.rb
sample_app_heroku_2/Procfile
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
sample_app_heroku_2/app/views/layouts/_header.html.erb
sample_app_heroku_2/db/seeds.rb
* 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/
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
IMPORTANT
* Change Git remote push and fetch locations to: sample_app_heroku_2.git
* Git show origin
* Git show remote location:
* Git push to Github:
* Bracket -> Change directory to -> sample_app_heroku_2
shell terminal
Firefox: http://localhost:3000/
sample_app_heroku_2/app/views/static_pages/home.html.erb
sample_app_heroku_2/app/views/layouts/_header.html.erb
sample_app_heroku_2/db/seeds.rb
shell terminal
sample_app_heroku_2/Gemfile
shell terminal
restart server
shell terminal for Github
shell terminal for heroku
Firefox: https://warm-ravine-91766.herokuapp.com/
Firefox: http://localhost:3000/
sample_app_heroku_2/Gemfile
shell terminal
sample_app_heroku_2/Gemfile
=============================================
Ch 6:
$ git log
sample_app_heroku_2/Gemfile
=============================================
Ch 7:
config/environments/production.rb
Procfile
=============================================
Ch 10:
* I updated: Gemfile, puma.rb, and production.rb files.
* 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
shell terminal: fetched the project from Github and stored in sample_app_heroku_2
$ cd ~* Showing Github remote origin for push and fetch
$ git clone https://github.com/jimmy2046/sample_app.git sample_app_heroku_2
$ 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* I had to disregard the master branch and replace with the "old-state" branch.
$ git add -A
$ git commit -m "Ch3 Updated Gemfile v2"
$ git checkout old-state
$ 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 logFirefox: http://localhost:3000/
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
$ 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* I updated Gemfile in Brackets and saved the file
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
$ 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
.profile
shell terminal
hello.go
shell terminal
References:
Ubuntu · golang/go Wiki · GitHub
https://github.com/golang/go/wiki/Ubuntu
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
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
test/fixtures/relationships.yml
test/integration/following_test.rb
shell terminal
test/controllers/relationships_controller_test.rb
app/controllers/relationships_controller.rb
app/views/users/_follow.html.erb
app/views/users/_unfollow.html.erb
app/controllers/relationships_controller.rb
config/application.rb
test/integration/following_test.rb
test/models/user_test.rb
app/models/user.rb
app/models/user.rb
app/models/user.rb
shell terminal
Github URL for sample_app project: https://github.com/jimmy2046/sample_app
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
Firefox: http://localhost:3000/
shell terminal
db/migrate/[timestamp]_create_relationships.rb
app/models/user.rb
app/models/relationship.rb
test/models/relationship_test.rb
app/models/relationship.rb
test/fixtures/relationships.yml
app/models/user.rb
test/models/user_test.rb
app/models/user.rb
app/models/user.rb
test/models/user_test.rb
db/seeds.rb
shell terminal
config/routes.rb
app/views/shared/_stats.html.erb
app/views/static_pages/home.html.erb
app/assets/stylesheets/custom.scss
Firefox: http://localhost:3000/
config/routes.rb
app/views/users/show.html.erb
Firefox: http://localhost:3000/users/2
Firefox: http://localhost:3000/users/6
test/controllers/users_controller_test.rb
app/controllers/users_controller.rb
Firefox: http://localhost:3000/users/1/following
Firefox: http://localhost:3000/users/1/followers
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
app/views/shared/_user_info.html.erb
app/views/shared/_micropost_form.html.erb
app/controllers/static_pages_controller.rb
app/views/shared/_error_messages.html.erb
app/views/users/new.html.erb
app/views/users/edit.html.erb
app/views/password_resets/edit.html.erb
app/views/shared/_error_message.html.erb
app/models/user.rb
app/controllers/static_pages_controller.rb
app/views/shared/_feed.html.erb
app/views/static_pages/home.html.erb
app/controllers/microposts_controller.rb
app/views/microposts/_micropost.html.erb
test/fixtures/microposts.yml
test/controllers/microposts_controller_test.rb
test/integration/microposts_interface_test.rb
Gemfile
app/models/micropost.rb
app/views/shared/_micropost_form.html.erb
app/controllers/microposts_controller.rb
app/views/microposts/_micropost.html.erb
app/uploaders/picture_uploader.rb
app/models/micropost.rb
app/views/shared/_micropost_form.html.erb
app/uploaders/picture_uploader.rb
app/uploaders/picture_uploader.rb
The URL address of the sample_app project was: https://github.com/jimmy2046/sample_app
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?shell terminal:
storage :fog
else
storage :file
end
$ 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
Firefox: http://localhost:3000/
db/migrate/
test/models/micropost_test.rbrequire 'test_helper'
app/models/micropost.rb
test/models/micropost_test.rb
app/models/micropost.rb
app/models/user.rb
test/models/micropost_test.rb
test/models/micropost_test.rb
test/fixtures/microposts.yml
app/models/micropost.rb
test/models/user_test.rb
app/models/user.rb
app/views/microposts/_micropost.html.erb
app/controllers/users_controller.rb
app/views/users/show.html.erb
db/seeds.rb
app/assets/stylesheets/custom.scss
The microposts of page 2 of user no#1, that was generated by db.Seed, was: http://localhost:3000/users/1?page=2
test/fixtures/microposts.yml
test/integration/users_profile_test.rb
app/controllers/users_controller.rb
config/routes.rb
test/controllers/microposts_controller_test.rb
app/controllers/application_controller.rb
app/controllers/users_controller.rb
DELETED action def logged_in_user
app/controllers/microposts_controller.rb
app/controllers/microposts_controller.rb
$ 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
Subscribe to:
Posts (Atom)
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 ...
-
It is still my beginning stage to learn Ruby on Rails. I found that is quite challenging to create a clickable image in html.erb (Ruby Embed...
-
sample app : Completed Ch. 13: User microposts (Part 2) app/views/static_pages/home.html.erb <% if logged_in? %> <div class=&...
-
Today, I finished up the chapter 4 of the book: Rails-flavored Ruby https://www.railstutorial.org/book/rails_flavored_ruby#cha-rails_flavore...