* I went back to myapp2 (https://github.com/jimmy2046/myapp2)
* I made and switched to a new branch named sign-up. It was just the same shell command.
$ git checkout -b sign-up
* I added a debug file in the home.html.erb file.
myapp2/app/views/static_pages/home.html.erb
<%= debug(params) if Rails.env.development? %>
* I added the resources in the routes.rb file.
myapp2/config/routes.rb
Rails.application.routes.draw do
get 'users/new'
root 'static_pages#home'
# home_path
get '/home', to: 'static_pages#home'
# help_path
get '/help', to: 'static_pages#help'
# about_path
get '/about', to: 'static_pages#about'
# contact_path
get '/contact', to: 'static_pages#contact'
# signup_path
get '/signup', to: 'users#new'
resources :users
end
The first part of this blog to to make a page to show user profile.
* I created a temporary html.erb file to show user's profile.myapp2/app/views/users/show.html.erb
<%= @user.first_name %>, <%= @user.last_name %>, <%= @user.email %>
* I added a new method show in the Users controller.
myapp2/app/controllers/users_controller.rb
def show
@user = User.find(params[:id])
end
* I create a sample user profile in Rails Console for testing.
$ rails console
User.create(first_name: "Jimmy", last_name: "Chong",
email: "jimmyc@example.com",
password: "foobar", password_confirmation: "foobar")
* I typed http://localhost:3000/users/1 in my Firefox browser to make sure the a user could be queried in the Sqlite database.
* I re-wrote show.html.erb to make a trendy style.
myapp2/app/views/users/show.html.erb
<% provide(:title, @user.first_name+" "+@user.last_name) %>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!--
Classic Template
http://www.templatemo.com/tm-488-classic
-->
<!-- load stylesheets -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,400"> <!-- Google web font "Open Sans" -->
<link rel="stylesheet" href="/assets/css/bootstrap.min.css"> <!-- Bootstrap style -->
<link rel="stylesheet" href="/assets/css/templatemo-style.css"> <!-- Templatemo style -->
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="tm-header">
<div class="container-fluid">
<div class="tm-header-inner">
<%= link_to("Sample App", root_path, :class => "navbar-brand tm-site-name") %>
<!-- <a href="#" class="navbar-brand tm-site-name">Sample App</a> -->
<!-- navbar -->
<nav class="navbar tm-main-nav">
<button class="navbar-toggler hidden-md-up" type="button" data-toggle="collapse" data-target="#tmNavbar">
☰
</button>
<div class="collapse navbar-toggleable-sm" id="tmNavbar">
<ul class="nav navbar-nav">
<li class="nav-item"><%= link_to "Home", root_path, class: "nav-link" %></li>
<li class="nav-item"><%= link_to "Help", help_path, class: "nav-link" %></li>
<li class="nav-item"><%= link_to "Log in", '#', class: "nav-link" %></li>
</ul>
</div>
</nav>
</div>
</div>
</div>
<div class="tm-about-img-container">
</div>
<section class="tm-section">
<div class="container-fluid">
<div class="row">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 text-xs-center">
<p class="tm-subtitle">
<%= @user.first_name %>, <%= @user.last_name %>, <%= @user.email %></p>
</div>
<%= link_to image_tag("rails.png", alt: "Rails logo"),
'http://rubyonrails.org/' %>
<%= debug(params) if Rails.env.development? %>
</div>
</div>
</section>
<footer class="tm-footer">
<div class="container-fluid">
<div class="row">
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-3 col-xl-3">
<div class="tm-footer-content-box tm-footer-links-container">
<h3 class="tm-gold-text tm-title tm-footer-content-box-title">Ruby on Rails Tutorial</h3>
<nav>
<ul class="nav">
<li>
<%= link_to("About", about_path, :class => "tm-footer-link") %>
</li>
<li>
<%= link_to("Contact", contact_path, :class => "tm-footer-link") %>
</li>
<li>
<a href="http://news.railstutorial.org/" class="tm-footer-link">News</a>
</li>
</ul>
</nav>
</div>
</div>
<!-- Add the extra clearfix for only the required viewport
http://stackoverflow.com/questions/24590222/bootstrap-3-grid-with-different-height-in-each-item-is-it-solvable-using-only
-->
<div class="clearfix hidden-lg-up"></div>
</div>
<div class="row">
<div class="col-xs-12 tm-copyright-col">
<p class="tm-copyright-text">Jimmy Chong 2017</p>
</div>
</div>
</div>
</footer>
<!-- load JS files -->
<script src="js/jquery-1.11.3.min.js"></script> <!-- jQuery (https://jquery.com/download/) -->
<script src="https://www.atlasestateagents.co.uk/javascript/tether.min.js"></script> <!-- Tether for Bootstrap, http://stackoverflow.com/questions/34567939/how-to-fix-the-error-error-bootstrap-tooltips-require-tether-http-github-h -->
<script src="js/bootstrap.min.js"></script> <!-- Bootstrap (http://v4-alpha.getbootstrap.com/) -->
</body>
</html>
* I copied the Gravatar helper method to Users helper file. I changed the original users.name variable to user.first_name.
myapp2/app/helpers/users_helper.rb
module UsersHelper
# Returns the Gravatar for the given user.
def gravatar_for(user)
gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}"
image_tag(gravatar_url, alt: user.first_name, class: "gravatar")
end
end
* In the same time, I coded the show.html.erb file to display the Gravatar of the user.
myapp2/app/views/users/show.html.erb
<% provide(:title, @user.first_name+" "+@user.last_name) %>
...
<h1>
<%= gravatar_for @user %>
<%= @user.first_name %> <%= @user.last_name %>
</h1>
...
* This was the preliminary version of user show page with templatemo CSS theme. (Firefox: http://localhost:3000/users/1)
The second part is to make the user sign up form.
* I copied the Users controller file from chapter 7 of the book, which included methods: show, new, create, and user_params.myapp2/app/controllers/users_controller.rb
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
end
def new
@user = User.new
end
def create
@user = User.new(user_params)
if @user.save
flash[:success] = "Welcome to the Sample App!"
redirect_to @user
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password,
:password_confirmation)
end
end
* Similarly, I copied the users/new.html.erb from the book to myapp2 project with the exception that I had to separate the name field into 2 independent first_name and last_name fields.
myapp2/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, url: signup_path) do |f| %>
<%= f.label :first_name %>
<%= f.text_field :first_name, class: 'form-control' %>
<%= f.label :last_name %>
<%= f.text_field :last_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>
* I created a shared view to display sign up error messages.
$ mkdir app/views/shared
* I copied the partial html.erb file from the book to display error message in HTML format.
myapp2/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 %>
* I added <%= render 'shared/error_messages' %> to new.html.erb Users view.
myapp2/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, url: signup_path) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :first_name %>
<%= f.text_field :first_name, class: 'form-control' %>
<%= f.label :last_name %>
<%= f.text_field :last_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>
* I did not understand why, but I added a line post '/signup', to: 'users#create' in config/routes.rb file to make the sign up form work.
myapp2/config/routes.rb
post '/signup', to: 'users#create'
* I didn't realized that, in the Users controller file, the permitted params.require
is (:first_name, :last_name, :email, :password, :password_confirmation)
NOT (:name, :email, :password, :password_confirmation)
I made the correction for the above code as well.
* Next, I generated the integration test for the Users sign up module. And then, I copied the Ruby codes from the book.
$ rails generate integration_test users_signup
* I added a gem 'rails-controller-testing' in the Gemfile for the testing of Rails controller.
gem 'rails-controller-testing'
* After I had added a line gem 'rails-controller-testing' to my Gemfile, I ran bundle install
$ bundle install
* In refer to the book's exercise, I added a signup route in the routes.rb file for responding to POST requests.
myapp2/config/routes.rb
post '/signup', to: 'users#create'
* I modified the form_for() line in the new.html.erb view file in the user controller.
myapp2/app/views/users/new.html.erb
<%= form_for(@user, url: signup_path) do |f| %>
* For successful user sign up, I copied the create method from the book to the Users controller file.
myapp2/app/controllers/users_controller.rb
def create
@user = User.new(user_params)
if @user.save
flash[:success] = "Welcome to the Sample App!"
redirect_to @user
else
render 'new'
end
end
* Then, I added the flash message (prompt) in the application layout file.
myapp2/app/controllers/users_controller.rb
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
end
def new
@user = User.new
end
def create
@user = User.new(user_params)
if @user.save
flash[:success] = "Welcome to the Sample App!"
redirect_to @user
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password,
:password_confirmation)
end
end
* I reset the database for the first sign up.
$ rails db:migrate:reset
* The sign up page in my own style.
* The sign up success page (user profile page) in my own style.
* I added one more test case for testing a legitimate sign up scenario.
myapp2/test/integration/users_signup_test.rb
test "valid signup information" do
get signup_path
assert_difference 'User.count', 1 do
post users_path, params: { user: { first_name: "Example",
last_name: "User",
email: "user@example.com",
password: "password",
password_confirmation: "password" } }
end
follow_redirect!
assert_template 'users/show'
end
* At the end of today's blog, I added all untracked files, committed all changes, went back to master branch, and merged sign-up branch.
$ git add -A
$ git commit -m "Finish user signup"
$ git checkout master
$ git merge sign-up
* I enabled SSL.
myapp2/config/environments/production.rb
config.force_ssl = true
* I enabled preload_app! in puma.rb
myapp2/config/puma.rb
preload_app!
* Finally, I ran a test and pushed it onto Github.
$ rails test
$ git add -A
$ git commit -m "Use SSL and the Puma webserver in production"
$ git push
* The Github address for the myapp2 project is
https://github.com/jimmy2046/myapp2
* Here are final version of some important programming files for today's blog:
myapp2/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, url: signup_path) do |f| %>
<%= render 'shared/error_messages' %>
<%= f.label :first_name %>
<%= f.text_field :first_name, class: 'form-control' %>
<%= f.label :last_name %>
<%= f.text_field :last_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>
myapp2/app/controllers/users_controller.rb
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
end
def new
@user = User.new
end
def create
@user = User.new(user_params)
if @user.save
flash[:success] = "Welcome to the Sample App!"
redirect_to @user
else
render 'new'
end
end
private
def user_params
params.require(:user).permit(:first_name, :last_name, :email, :password,
:password_confirmation)
end
end
myapp2/config/routes.rb
Rails.application.routes.draw do
get 'users/new'
root 'static_pages#home'
# home_path
get '/home', to: 'static_pages#home'
# help_path
get '/help', to: 'static_pages#help'
# about_path
get '/about', to: 'static_pages#about'
# contact_path
get '/contact', to: 'static_pages#contact'
# signup_path
get '/signup', to: 'users#new'
post '/signup', to: 'users#create'
resources :users
end
myapp2/app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title><%= full_title(yield(:title)) %></title>
<%= csrf_meta_tags %>
<%= stylesheet_link_tag 'application', media: 'all',
'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>
<body>
<div class="container">
<% flash.each do |message_type, message| %>
<div class="alert alert-<%= message_type %>"><%= message %></div>
<% end %>
<%= yield %>
</div>
</body>
</html>
myapp2/test/integration/users_signup_test.rb
require 'test_helper'
class UsersSignupTest < ActionDispatch::IntegrationTest
require 'test_helper'
class UsersSignupTest < ActionDispatch::IntegrationTest
test "invalid signup information" do
get signup_path
assert_no_difference 'User.count' do
post users_path, params: { user: { first_name: "",
last_name: "",
email: "user@invalid",
password: "foo",
password_confirmation: "bar" } }
end
assert_template 'users/new'
end
test "valid signup information" do
get signup_path
assert_difference 'User.count', 1 do
post users_path, params: { user: { first_name: "Example",
last_name: "User",
email: "user@example.com",
password: "password",
password_confirmation: "password" } }
end
follow_redirect!
assert_template 'users/show'
end
end
end
myapp2/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 %>
Very informative blog and useful article thank you for sharing with us , keep posting learn more Ruby on Rails Online Training India
ReplyDelete