見出し画像

railsチュートリアル魔改造編 第16章 新規登録魔改造

第16章 新規登録魔改造編

新規登録画面を魔改造していきます。

いつものようにトピックブランチを作成します。

git checkout -b rails-makaizou-16

16.1 リンクのおさらい

リンクについておさらいします。
新規登録画面に飛ぶためのコードは、以下のようになっています。
<%# 新規登録ボタンを赤色(danger)にする %>
<%= link_to "新規登録", signup_path, class: "btn btn-lg btn-danger signup " %>

16.1.1 どこから新規登録画面に飛ぶのか

signup_pathに飛びますが、
では一体、signup_pathはなにを表しているのでしょう?

rails routesコマンドを実行すると、以下のようになっています。

ログ
----------------------------
ec2-user:~/environment/sample_app (rails-makaizou-16) $ rails routes
                Prefix Verb   URI Pattern                             Controller#Action
                  root GET    /                                       static_pages#home
                  help GET    /help(.:format)                         static_pages#help
                 about GET    /about(.:format)                        static_pages#about
               contact GET    /contact(.:format)                      static_pages#contact
                signup GET    /signup(.:format)                       users#new
                 login GET    /login(.:format)                        sessions#new
                       POST   /login(.:format)                        sessions#create
                logout DELETE /logout(.:format)                       sessions#destroy
        following_user GET    /users/:id/following(.:format)          users#following
        followers_user GET    /users/:id/followers(.:format)          users#followers
                 users GET    /users(.:format)                        users#index
                       POST   /users(.:format)                        users#create
              new_user GET    /users/new(.:format)                    users#new
             edit_user GET    /users/:id/edit(.:format)               users#edit
                  user GET    /users/:id(.:format)                    users#show
                       PATCH  /users/:id(.:format)                    users#update
                       PUT    /users/:id(.:format)                    users#update
                       DELETE /users/:id(.:format)                    users#destroy
edit_account_activation GET    /account_activations/:id/edit(.:format) account_activations#edit
       password_resets POST   /password_resets(.:format)              password_resets#create
    new_password_reset GET    /password_resets/new(.:format)          password_resets#new
   edit_password_reset GET    /password_resets/:id/edit(.:format)     password_resets#edit
        password_reset PATCH  /password_resets/:id(.:format)          password_resets#update
                       PUT    /password_resets/:id(.:format)          password_resets#update
            microposts POST   /microposts(.:format)                   microposts#create
             micropost DELETE /microposts/:id(.:format)               microposts#destroy
         relationships POST   /relationships(.:format)                relationships#create
          relationship DELETE /relationships/:id(.:format)            relationships#destroy
ec2-user:~/environment/sample_app (rails-makaizou-16) $ 
----------------------------


プレフィックス+"_path"とすることで、そのパスが文字列で取得できます。
つまり、/signupが取得できるという訳ですね。それでまず一番最初にどこに飛ぶか。

新規登録ボタンを押すと、まずusers_controller.rbのnewアクションが実行されます。
その後、app/views/users/new.html.erbに飛びます。

ここで、1行ずつ、どの行がどのルーティングとなっているかを確認します。

全コメントアウト
----------------------------
rails routes
You don't have any routes defined!
Please add some routes in config/routes.rb.
For more information about routes, see the Rails guide: http://guides.rubyonrails.org/routing.html.
----------------------------
root   'static_pages#home'のみ
----------------------------
Prefix Verb URI Pattern Controller#Action
 root GET  /           static_pages#home
----------------------------
get    '/help',    to: 'static_pages#help'のみ
----------------------------
Prefix Verb URI Pattern     Controller#Action
 help GET  /help(.:format) static_pages#help
----------------------------
resources :users
----------------------------
  Prefix Verb   URI Pattern               Controller#Action
   users GET    /users(.:format)          users#index
         POST   /users(.:format)          users#create
new_user GET    /users/new(.:format)      users#new
edit_user GET    /users/:id/edit(.:format) users#edit
    user GET    /users/:id(.:format)      users#show
         PATCH  /users/:id(.:format)      users#update
         PUT    /users/:id(.:format)      users#update
         DELETE /users/:id(.:format)      users#destroy
----------------------------
resources :account_activations
----------------------------
                Prefix Verb   URI Pattern                             Controller#Action
   account_activations GET    /account_activations(.:format)          account_activations#index
                       POST   /account_activations(.:format)          account_activations#create
new_account_activation GET    /account_activations/new(.:format)      account_activations#new
edit_account_activation GET    /account_activations/:id/edit(.:format) account_activations#edit
    account_activation GET    /account_activations/:id(.:format)      account_activations#show
                       PATCH  /account_activations/:id(.:format)      account_activations#update
                       PUT    /account_activations/:id(.:format)      account_activations#update
                       DELETE /account_activations/:id(.:format)      account_activations#destroy
----------------------------

resourcesはルーティングがスッキリして便利ですが、どのようなルーティングになるか知らずに使うと何してるのか分からないというデメリットがあるので使用する際は注意が必要です。

16.2 文字魔改造

目に見えている文字列をどんどん変更していく。

16.2.1 Signup

見出しのSign upを新規登録にする。
ここで、一つ問題が発生する。
railsチュートリアルで作成したminitestにより、rails testが失敗するはずである。

以下のように変更する

リスト16.01: 見出しに対するテストをしないようにする
/sample_app/test/integration/site_layout_test.rb
----------------------------
require 'test_helper'
class SiteLayoutTest < ActionDispatch::IntegrationTest
 test "layout links" do
   get root_path
   assert_template 'static_pages/home'
   assert_select "a[href=?]", root_path, count: 2
   assert_select "a[href=?]", help_path
   assert_select "a[href=?]", about_path
   assert_select "a[href=?]", contact_path
   
   # コンタクトパス
   get contact_path
   assert_select "title", full_title("Contact")
   
   #サインアップパス
   get signup_path
   #assert_select "title", full_title("Sign up")
 end
end

あとで表示文字列変更したいと思った時の手間を考えて、コメントアウトにした。

これでrails testが通るはずである。

あとは、h1に囲まれたSign upを新規登録に変更するだけである。

16.2.2 Name

/sample_app/app/views/users/new.html.erb
<%= f.label :name %>

<%= f.label :name, "名前" %>
にするだけでおk

16.2.3 Email

/sample_app/app/views/users/new.html.erb
メールアドレスにする

16.2.4 Password

/sample_app/app/views/users/new.html.erb
パスワードにする


16.2.5 Confirmation

/sample_app/app/views/users/new.html.erb
パスワード(再入力)にする


16.3 エラー文魔改造

エラー文を全部魔改造します。
できるのか?

https://qiita.com/Ushinji/items/242bfba84df7a5a67d5b
のように、それ用のgemがあるが、今回は手打ちで全部エラー文を処理で分岐して表示する。
非効率だけどね。

16.3.1 どこにエラー文が出るか

下記パーシャルを呼び出して、実現している。
/sample_app/app/views/shared/_error_messages.html.erb

any?とは?(復習)
any?は、要素の中に一つでもnilでないものがある場合を指す
div id="error_explanation"は何を指す?
explanationは説明を指す
custom.cssに#error_explanationがある。

16.3.2 英語のエラー文を全て日本語に

/sample_app/app/views/shared/_error_messages.html.erb
で、msgとエラーメッセージを比較して、対応する日本語のエラーを表示する

16.4 ボタン文字列魔改造

ボタンを赤色にする。

16.4.1 Create my account

<%= f.submit "魔改造アカウントを作成する", class: "btn btn-danger" %>にする

16.5 最後に


git add -A
git status

ログ
----------------------------
       modified:   app/assets/stylesheets/custom.scss
       modified:   app/controllers/static_pages_controller.rb
       modified:   app/controllers/users_controller.rb
       modified:   app/views/shared/_error_messages.html.erb
       modified:   app/views/users/new.html.erb
       modified:   config/routes.rb
       modified:   test/integration/site_layout_test.rb
----------------------------


git commit -m "add 16"
git checkout master
修正前ファイルをブログ用に保存しておく
git merge rails-makaizou-16
修正後ファイルをブログ用に保存しておく
git push origin master

source <(curl -sL https://cdn.learnenough.com/heroku_install)
git push heroku master

16.5.1 修正後


リスト16.02: app/assets/stylesheets/custom.scss
----------------------------
@import "bootstrap-sprockets";
@import "bootstrap";
/* mixins, variables, etc. */
$gray-medium-light: #eaeaea;
@mixin box_sizing {
 -moz-box-sizing:    border-box;
 -webkit-box-sizing: border-box;
 box-sizing:         border-box;
}
/* universal */
/* 共通設定 */
/* 背景 */
body {
 /* 文字の種類 */
 font-family: "游明朝";
 
 /* 文字色 */
 color: #555555;
   
 /* 文字の幅 */
 letter-spacing: 1px;
 /* 背景色 */
 background-color:#FFEEEE;
 
 /* 上からの空白 */
 padding-top: 100px;
}
section {
 overflow: auto;
}
textarea {
 resize: vertical;
}
/* typography */
h1, h2, h3, h4, h5, h6 {
 /* 行の高さ */
 line-height: 1;
}
h1 {
 font-size: 3em;
/*  letter-spacing: -2px;*/
 margin-bottom: 30px;
 text-align: center;
}
h2 {
 font-size: 1.2em;
 letter-spacing: -1px;
 margin-bottom: 30px;
 text-align: center;
 font-weight: normal;
 color: $gray-light;
}
p {
 font-size: 1.1em;
 line-height: 1.7em;
}
/* home中央文字 */
.center {
 /* 相対位置 */
 position: relative;
 /* 文字の種類 */
 font-family: "游明朝";
 /* テキスト変換 */
 text-transform: uppercase;
 /* 文字の色 */
 color: #EEEEEE;
 /* 中央揃え */
 text-align: center;
 /* タイトル */
 h1
 {
   /* 文字の幅 */
   letter-spacing: 5px;
   /* 透明度 */
   opacity: 0.8;
   
   /* 絶対位置 */
   position: absolute;
   /* 位置 */
   top: 20%;
   left: 50%;
   /* X方向、Y方向にどれだけずらすか */
   -ms-transform: translate(-50%,-50%);
   -webkit-transform: translate(-50%,-50%);
   transform: translate(-50%,-50%);
   /* 改行させない */
   white-space: nowrap;
 }
 
 /* サブタイトル */
 h2{
   /* 文字の色 */
   color: #AAAAAA;
   /* 文字の幅 */
   letter-spacing: 5px;
   /* 透明度 */
   opacity: 0.9;
   /* 絶対位置 */
   position: absolute;
   /* 上からの位置 */
   top: 70%;
   /* 左からの位置 */
   left: 50%;
   /* X方向、Y方向にどれだけずらすか */
   -ms-transform: translate(-50%,-50%);
   -webkit-transform: translate(-50%,-50%);
   transform: translate(-50%,-50%);
 }
 img{
   /* 背景のサイズ */
   width: 100%;
 }
 /* サインアップボタン */
 .signup{
   /* 絶対位置 */
   position: absolute;
   /* 上からの位置 */
   top: 90%;
   
   /* 左からの位置 */
   left: 50%;
   
   /* X方向、Y方向にどれだけずらすか */
   -ms-transform: translate(-50%,-50%);
   -webkit-transform: translate(-50%,-50%);
   transform: translate(-50%,-50%);
 }
}
/* 画面が小さいとき */
@media(max-width:1000px){
 /* home中央文字 */
 .center {
   
   /* タイトル */
   h1 {
     /* 文字サイズ */
     font-size: 1.5em;
   }
   
   /* サブタイトル */
   h2 {
     /* 文字サイズ */
     font-size: 0.6em;
   }
   
   /* 新規登録ボタン */
   .signup{
     /* 文字サイズ */
     font-size: 1em;
     
     /* 内側空白 */
     padding:3px;
   }
 }
}

/* header */
header{
 /* 文字の種類 */
 font-family: "游ゴシック";
 /* ロゴの文字列に対するCSSです */
 #logo {
   /* 寄せ方 */
   float: left;
   
   /* 線の外側の右側の余白 */
   margin-right: 20px;
   
   /*線の内側の上側の余白  */
   padding-top: 10px;
   
   /* フォントの大きさ */
   font-size: 1.6em;
   
   /* 文字色 */
   color: #444444;
 
   /* テキスト変換 */
   text-transform: lowercase;
   
   /* 文字の幅 */
   letter-spacing: 5px;
   
   /* 文字の太さ */
   font-weight: normal;
   /* マウスカーソルを乗せたときのスタイル */
   &:hover {
     color: #AAAAAA;
     text-decoration: none;
   }
 }
}
/* footer */
footer {
 /* 文字の種類 */
 font-family: "游ゴシック";
 /* 線の外の上からの空白 */
 margin-top: 45px;
 /* 線の中の上からの空白 */
 padding-top: 5px;
 /* 線 */
 border-top: 1px solid #AAAAAA;
 /* 文字色 */
 color: $gray-light;
 /* リンク */
 a {
   /* 文字色 */
   color: $gray;
   
   /* マウスを乗せたら */
   &:hover {
     /* 文字色 */
     color: $gray-darker;
   }
 }
 /* 左下 */
 small {
   /* 左寄せ */
   float: left;
 }
 
 /* 右下 */
 ul {
   /* 右寄せ */
   float: right;
   /* 黒点なし */
   list-style: none;
   li {
     /* 左寄せ */
     float: left;
     
     /* 間隔 */
     margin-left: 30px;
   }
 }
}
.debug_dump {
 clear: both;
 float: left;
 width: 100%;
 margin-top: 45px;
 @include box_sizing;
}
/* sidebar */
aside {
 section.user_info {
   margin-top: 20px;
 }
 section {
   padding: 10px 0;
   margin-top: 20px;
   &:first-child {
     border: 0;
     padding-top: 0;
   }
   span {
     display: block;
     margin-bottom: 3px;
     line-height: 1;
   }
   h1 {
     font-size: 1.4em;
     text-align: left;
     letter-spacing: -1px;
     margin-bottom: 3px;
     margin-top: 0px;
   }
 }
}
.gravatar {
 float: left;
 margin-right: 10px;
}
.gravatar_edit {
 margin-top: 15px;
}
.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;
}
/* forms */
input, textarea, select, .uneditable-input {
 border: 1px solid #bbb;
 width: 100%;
 margin-bottom: 15px;
 @include box_sizing;
}
input {
 height: auto !important;
}
/* 新規登録とかのエラー文字列 */
#error_explanation {
 /* 文字色:赤 */
 color: red;
 
 /* リスト */
 ul {
   /* 文字色:オレンジ */
   color: #E66D00;
   
   /* 空白:下に30px */
/*    margin: 0 0 30px 0;*/
 }
}
.field_with_errors {
 @extend .has-error;
 .form-control {
   color: $state-danger-text;
 }
}
.checkbox {
 margin-top: -10px;
 margin-bottom: 10px;
 span {
   margin-left: 20px;
   font-weight: normal;
 }
}
#session_remember_me {
 width: auto;
 margin-left: 0;
}
/* Users index */
.users {
 list-style: none;
 margin: 0;
 li {
   overflow: auto;
   padding: 10px 0;
   border-bottom: 1px solid $gray-lighter;
 }
}
/* 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;
 }
}

リスト16.03: app/controllers/static_pages_controller.rb
----------------------------
class StaticPagesController < ApplicationController
 # ルートページ
 def home
   # ログイン中?
   if logged_in?
     # 現在ログイン中のユーザーのマイクロポストを取得する
     @micropost  = current_user.microposts.build
     # ページネーション用の準備を行う
     @feed_items = current_user.feed.paginate(page: params[:page])
   end
 end
 def help
 end
 def about
 end
 def contact
 end
end

リスト16.04: app/controllers/users_controller.rb
----------------------------
class UsersController < ApplicationController
 before_action :logged_in_user, only: [:index, :edit, :update, :destroy,
                                       :following, :followers]
 before_action :correct_user,   only: [:edit, :update]
 before_action :admin_user,     only: :destroy
 
 def index
   @users = User.where(activated: true).paginate(page: params[:page])
 end
 def show
   @user = User.find(params[:id])
   @microposts = @user.microposts.paginate(page: params[:page])
 end
 
 # /signup で呼ばれるアクション
 # app/views/users/new.html.erbへ
 def new
   #ユーザーを新規に作成する
   @user = User.new
 end
 
 def create
   @user = User.new(user_params)
   if @user.save
     @user.send_activation_email
     flash[:info] = "Please check your email to activate your account."
     redirect_to root_url
   else
     render 'new'
   end
 end
 def edit
 end
 def update
   if @user.update_attributes(user_params)
     flash[:success] = "Profile updated"
     redirect_to @user
   else
     render 'edit'
   end
 end
 
 def destroy
   User.find(params[:id]).destroy
   flash[:success] = "User deleted"
   redirect_to users_url
 end
 
 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
 private
   def user_params
     params.require(:user).permit(:name, :email, :password,
                                  :password_confirmation)
   end
   # beforeアクション
   # 正しいユーザーかどうか確認
   def correct_user
     @user = User.find(params[:id])
     redirect_to(root_url) unless current_user?(@user)
   end
   
       # 管理者かどうか確認
   def admin_user
     redirect_to(root_url) unless current_user.admin?
   end
end
リスト16.05: app/views/shared/_error_messages.html.erb
----------------------------
<%# objectはform_forの|f|からf.objectで取り出したもの %>
<%# エラーあり? %>
<% if object.errors.any? %>
 <%# エラー説明文 %>
 <div id="error_explanation">
   <%# エラーの数を表す %>
   <div class="alert alert-danger">
     入力いただいた情報に<%= object.errors.count %>つ誤りがあります。
     <%# エラーリスト %>
     <ul>
       <%# エラーの数だけループ %>
       <% object.errors.full_messages.each do |msg| %>
         <li>
           <% if msg == "Name can't be blank" %>
             名前が空白のようです。
           <% elsif msg == "Email can't be blank" %>
             メールアドレスが空白のようです。
           <% elsif msg == "Email is invalid" %>
             無効なメールアドレスのようです。
           <% elsif msg == "Password can't be blank" %>
             パスワードが空白のようです。
           <% elsif msg == "Password confirmation doesn't match Password" %>
             2つのパスワードが一致していないようです。
           <% elsif msg == "Password is too short (minimum is 6 characters)" %>
             パスワードが短いようです。6文字以上にお願いします。
           <% elsif msg == "Name is too long (maximum is 50 characters)" %>
             名前が長いようです。50文字以内にお願いします。
           <% elsif msg == "Email is too long (maximum is 255 characters)" %>
             メールアドレスが長いようです。255文字以内にお願いします。
           <% elsif msg == "Email has already been taken" %>
             既に登録いただいているアカウントのようです。
           <% else %>
             <%= msg %>
           <% end %>
         </li>
       <% end %>
     </ul>
   </div>
 </div>
<% end %>

リスト16.06: app/views/users/new.html.erb
----------------------------
<%#
 # /signup で呼ばれるアクション
 # app/views/users/new.html.erbへ
 def new
   #ユーザーを新規に作成する
   @user = User.new
 end
%>
<%# 見出しを新規登録にする %>
<% provide(:title, '新規登録') %>
<%# 見出しを新規登録にする %>
<h1>新規登録</h1>
<%# Bootstrapの機能で、12列に何を割り当てるか決める %>
<div class="row">
 <%# 空白3-入力スペース6-空白3の構成にする %>
 <div class="col-md-6 col-md-offset-3">
   <%# フォームを作成し、@userにデータを入れていく  %>
   <%= 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, "パスワード(再入力)" %>
     <%= f.password_field :password_confirmation, class: 'form-control' %>
     <%# パスワード(再入力) %>
     <%= f.submit "魔改造アカウントを作成する", class: "btn btn-danger" %>
   <% end %>
 </div>
</div>

リスト16.07: config/routes.rb
----------------------------
Rails.application.routes.draw do
 
 # ルートページ
 root   'static_pages#home'
 
 get    '/help',    to: 'static_pages#help'
 get    '/about',   to: 'static_pages#about'
 get    '/contact', to: 'static_pages#contact'
 
 # 新規登録ページは、/signup
 # app/controllers/users_controller.rbのnewアクションへ
 get    '/signup',  to: 'users#new'
 
 
 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]
 resources :relationships,       only: [:create, :destroy]
end

リスト16.08: test/integration/site_layout_test.rb
----------------------------
require 'test_helper'
class SiteLayoutTest < ActionDispatch::IntegrationTest
 test "layout links" do
   get root_path
   assert_template 'static_pages/home'
   assert_select "a[href=?]", root_path, count: 2
   assert_select "a[href=?]", help_path
   assert_select "a[href=?]", about_path
   assert_select "a[href=?]", contact_path
   
   # コンタクトパス
   get contact_path
   assert_select "title", full_title("Contact")
   
   #サインアップパス
   get signup_path
   #assert_select "title", full_title("Sign up")
 end
end


16.5.2 本章のまとめ


ルーティングについての理解を深めることができた。
pathについての理解を深めることができた。
resourcesを使わないと、ルーティングがどのようになるか理解できた。
rails testを習慣的に行うことによって、minitestの修正を漏れなく行うことができた。
アナログなやり方だが、英語のエラー文を自分好みのエラー文に差し替えることができた。
Bootstrapを使うと、エラーを表示する時に使う枠組みはたぶん変えられない。

修正前

001 修正前

修正後

002 修正後


この記事が気に入ったらサポートをしてみませんか?