ブランチの退避方法(git、github)

内容

構成を変えるため、再度要件定義やDB設計を行う。

現在作業しているブランチを退避

1. 変更を退避

投稿一覧表示機能のブランチで作業中であったが、作業が中途半端でコミットしたくないため、stashを使用し退避させる
退避させた後は、ブランチを切り替えて作業を行う
ターミナル

% git stash -u
# -uは--include-untrackedの略

2. 退避した作業一覧

以下のコマンドで退避した作業の一覧を見ることができる
ターミナル

git stash list

3. 他のブランチで作業

作業後、コンフリクトが生じたら、resolve conflictsで都度修正
修正後、mark as resolved→commit merge

4. 退避した作業を元に戻すと同時に、stashのリストから消去

元に戻したいブランチに切り替えて、コマンドを入力する
stash名(stash@{0})を省略すると、直近にstashした情報を消すことができる
ターミナル

git stash pop stash@{0}

要件定義、DB設計のやり直し

1. 要件定義の修正

機能、表示等の洗い出し

2. 画面遷移図、ER図の修正

draw.ioで修正

3. READMEの修正

README.mdファイルを修正

新規投稿機能のやり直し

1. postsテーブルの修正

マイグレーションファイルをrails db:rollbackしてから修正し、rails db:migrate
※上記方法はローカル環境ではまだいいが、本番環境ではやらない方がいいらしい
→デプロイ後のテーブル変更は、基本的にマイグレーションファイルを追加することで対応するとのこと

2. ビュー、CSSの修正およびバリデーションの設定

postsテーブルのカラムを変更したため、ビュー、CSS、コントローラーも大幅に修正
その際、ビューの修正は完璧だったはずだが、Completed 500 Internal Server Errorが出て、フォームの値は遅れているのにトップページが表示されずにエラーとなった
結論バリデーションを設定し直していなかっただけだった→そのまま修正

3. Postモデルの単体テストコードの修正

テストコードも全体的に修正した

4. rubocop

次回

stashしたブランチを元に戻し、投稿一覧表示機能の修正から

新規投稿機能および投稿一覧表示機能

内容

新規投稿機能、投稿一覧表示機能の実装を行う。

新規投稿機能の実装の続きから

2. ビュー、CSSの作成

ビューファイルを作成し、編集
ルーティングを設定
postsコントローラーでnewアクション、createアクションの中身を定義
※その際、params.require.permit.mergeでデータを取得
今回のアプリでは、投稿一覧ページと投稿詳細ページ以外は、ログインしているユーザーしか遷移できないようにする
posts_controller.rb

before_action :authenticate_user!, execpt: [:index, :show]

3. バリデーションの設定

バリデーションをpost.rbに記述
URLのバリデーション設定はネットで調べたら上の正規表現が出てきたが、rubocopでコードを自動整形したところこの表現は廃止されていて訂正された
よって、下の正規表現を用いること

# 廃止
validates :url, format: /\A#{URI::regexp(%w(http https))}\z/
# 以下を使う
validates :url, format: /\A#{URI::DEFAULT_PARSER.make_regexp(%w[http https])}\z/

4. Postモデルの単体テストコードの実装

spec/factoriesディレクトリ内のposts.rbファイルに投稿情報をFactoryBotで指定
FakerでランダムなURL、0より大きい数値を作成したい場合、以下の通り
posts.rb

{ Faker::Internet.url(scheme: 'https') }
{ Faker::Number.positive }

テストコードをpost_spec.rbファイルに記述
実装が完了後、rspecコマンドでテストを実行
ターミナル

% bundle exec rspec spec/models/post_spec.rb

5. Rubocopでコードを自動整形

ターミナル

% rubocop -a

投稿一覧表示機能の実装

1. ビュー、CSSの作成

ビューファイルを編集
postsコントローラーのindexアクションを記述

次回

投稿一覧ページのビューで迷い中。構成を変えるかも。

参考

link_toのリンク先を別タブで表示したい時

同じタブでリンクを開く場合、以下の通り
index.html.erb

<%= link_to "表示したい文字", "リンク先のURL" %>
# もしくは
<%= link_to "表示したい文字", "リンク先のURL", target: :_self %>
# target: :_selfは、リンクのデフォルト値のため省略可能

別タブで開きたい場合、以下のように記述する
index.html.erb

<%= link_to "表示したい文字", "リンク先のURL", target: :_blank %>

しかしこれだけだとセキュリティ面、パフォーマンス面に問題あり!
以下のように追記する必要がある
index.html.erb

<%= link_to "表示したい文字", "リンク先のURL", target: :_blank, rel: "noopener noreferrer" %>

ユーザー管理機能(Deviseの導入)

内容

Deviseを使用したユーザー管理機能および新規投稿機能の実装を行う。

ユーザー管理機能の実装

1. Deviseを導入

Gemfile

# 1番下に記述
gem 'devise'

ターミナル

% bundle install
% rails s

2. Userモデルを作成し、マイグレーションファイルを編集

ターミナル

# modelではなくdeviseになることに注意
% rails g devise user

DB設計を参考に、必要なカラムをマイグレーションファイルに記述
ターミナル

% rails db:migrate
% rails s

3. ビュー、CSSの作成

ターミナル

rails g devise:views

ビューを編集
サインアップ後トップページへログインするため、必要なコントローラーとアクション、ビューを作成
ターミナル

rails g controller posts index

rootパスの設定
routes.rb

root to: 'posts#index'

トップページのビューも編集
emailとpassword以外のカラム情報を保存できるよう記述
application_controller

before_action :configure_permitted_parameters, if: :devise_controller?

private
def configure_permitted_parameters
  devise_parameter_sanitizer.permit(:sign_up, keys: [:nickname, :last_name, :first_name, :last_name_reading, :first_name_reading, :birthday])
end

4. バリデーションの設定

emailとpassword以外のバリデーションをuser.rbに記述

5. Userモデルの単体テストコードの実装

Gemfile

group :development, :test do
  gem 'rspec-rails'
  gem 'factory-bot-rails'
  gem 'faker'
end

ターミナル

% bundle install
% rails s
% rails g rspec:install

.rspec

--format documentation

specディレクトリ内にfactoriesディレクトリを作成し、その中にusers.rbファイルを作成
ユーザー情報をFactoryBotで指定
テストコードを記述するファイルを用意
ターミナル

% rails g rspec:model user

テストコードをuser_spec.rbファイルに記述
実装が完了後、rspecコマンドでテストを実行
ターミナル

% bundle exec rspec spec/models/user_spec.rb

新規投稿機能の実装

1. Postモデルを作成し、マイグレーションファイルを編集

ターミナル

% rails g model post

DB設計を参考に、必要なカラムをマイグレーションファイルに記述
ターミナル

% rails db:migrate
% rails s

2. ビュー、CSSの作成

ビューファイルを作成し、編集

次回

新規投稿機能のビューファイル編集の途中から。

参考

FactoryBotでランダムな値を生成する時、Fakerを使用する。
日本語対応もできるが、名前のふりがな等は対応していない。
そこでgimeiというgemを使用すれば、日本語の名前やふりがなも簡単に導入できるようになる。

アプリ作成の事前準備・DB設計

内容

本日よりオリジナルアプリ作成に入るので、今後の備忘録として実装手順、詰まったところ等をまとめる。

本日の実装

1. 新規アプリケーション作成

ターミナル

% cd ~/作成したいディレクトリ名
# railsのバージョンと、-dオプションでMySQLの使用を明示
% rails _6.0.0_ new アプリケーション名 -d mysql
# ここでdatabase.ymlのencodingを、utf8mb4→utf8に編集する
% cd 作成したアプリケーション名
% pwd
% rails db:create

2. リポジトリを作成

GitHub Desktopを用いてローカルリポジトリを作成する
② first commitというコミットメッセージでcommitする
③ アプリケーションと同名のリモートリポジトリを作成する
④ pushする

3. GitHubのプロジェクトボードに実装機能を記述

4. 自動整形ツールの導入

Rubyの静的コード解析ツールであるRubocopを導入する。
Gemfile

group :development do
  gem 'rubocop', require: false
end

ターミナル

% bundle install
% touch .rubocop.yml

Rubocopの設定を行う。以下コピペ。
.rubocop.yml

AllCops:
# 除外するディレクトリ(自動生成されたファイル)
# デフォルト設定にある"vendor/**/*"が無効化されないように記述
 Exclude:
   - "vendor/**/*" # rubocop config/default.yml
   - "db/**/*"
   - "config/**/*"
   - "bin/*"
   - "node_modules/**/*"
   - "Gemfile"


# 1行あたりの文字数をチェックする
Layout/LineLength:
 Max: 130
# 下記ファイルはチェックの対象から外す
 Exclude:
   - "Rakefile"
   - "spec/rails_helper.rb"
   - "spec/spec_helper.rb"

# RSpecは1つのブロックあたりの行数が多くなるため、チェックの除外から外す
# ブロック内の行数をチェックする
Metrics/BlockLength:
 Exclude:
   - "spec/**/*"

# Assignment: 変数への代入
# Branch: メソッド呼び出し
# Condition: 条件文
# 上記項目をRubocopが計算して基準値を超えると警告を出す(上記頭文字をとって'Abc')
Metrics/AbcSize:
 Max: 50

# メソッドの中身が複雑になっていないか、Rubocopが計算して基準値を超えると警告を出す
Metrics/PerceivedComplexity:
 Max: 8

# 循環的複雑度が高すぎないかをチェック(ifやforなどを1メソッド内で使いすぎている)
Metrics/CyclomaticComplexity:
 Max: 10

# メソッドの行数が多すぎないかをチェック
Metrics/MethodLength:
 Max: 30

# ネストが深すぎないかをチェック(if文のネストもチェック)
Metrics/BlockNesting:
 Max: 5

# クラスの行数をチェック(無効)
Metrics/ClassLength:
 Enabled: false

# 空メソッドの場合に、1行のスタイルにしない NG例:def style1; end
Style/EmptyMethod:
 EnforcedStyle: expanded

# クラス内にクラスが定義されていないかチェック(無効)
Style/ClassAndModuleChildren:
 Enabled: false

# 日本語でのコメントを許可
Style/AsciiComments:
 Enabled: false

# クラスやモジュール定義前に、それらの説明書きがあるかをチェック(無効)
Style/Documentation:
 Enabled: false

# %i()構文を使用していないシンボルで構成される配列リテラルをチェック(無効)
Style/SymbolArray:
 Enabled: false

# 文字列に値が代入されて変わっていないかチェック(無効)
Style/FrozenStringLiteralComment:
 Enabled: false

# メソッドパラメータ名の最小文字数を設定
Naming/MethodParameterName:
 MinNameLength: 1

ちなみに、Rubocopを実行するにはターミナルで以下のコマンドを実行する。
【例】ターミナル

# Rubocopを実行
% bundle exec rubocop

チェック内容を自動で修正させることもできる。
【例】ターミナル

# Rubocopを実行し、check内容を自動修正
% bundle exec rubocop -a

5. デフォルトの記述を削除

JavaScriptファイルの処理が正常に動作しないことを防ぐため、turbolinksを無効化しておく。
app/javascript/packs/application.js

// 省略
require("@rails/ujs").start()
// require("turbolinks").start() //この行を削除する
require("@rails/activestorage").start()
require("channels")

// 省略

6. Gitで不要なファイルを除外

不要な変更履歴である.DS_Storeという隠しファイルを、Gitで管理しないようにする。
.gitignoreファイルの一番下の行に、.Ds_Storeと追記する。
.gitignore

# 1番下の行
.Ds_Store

7. DB設計

画面遷移図を作成する。
ER.dioファイルを作成し、ER図を作成後、READMEに設計情報を記述する。

次回

DB設計をもとに、必要な機能から順次実装していく。まずはユーザー管理機能からかな。

所感

今回の実装の流れが絶対ではないが、さっと実装に移るためにもこの流れを覚えておきたいと感じた。

※注意点

開発環境で以下の変更を行なった場合、必ずローカルサーバーを再起動する必要がある(ローカルサーバーを起動するタイミングに1度だけ読みこまれるため)。
- Rubyバージョンの変更
- テーブル、カラム情報の変更
- Gemの導入状況の変更

企画・要件定義

内容

アプリ作成のための準備事項を、備忘録としてまとめる。

事前準備内容

1. アプリ案をメモ

思いついたアプリ案をメモアプリにすべて書き込んだ。
難しそうなものからしょーもないものまで、とにかく思いついたらメモ。
今後もこれ作ってみたいな、と思ったら随時追記していく。
考えたものの中から1つ、アプリケーションを選択した。

2. 企画を行う

まずペルソナを設定した。
今回は、「性別・年齢」、「職業」、「趣味」、「日頃の生活」で考えてみたが、必要に応じて項目を考える。
その後、設定したペルソナが解決したい課題、なぜその解決が必要か、解決する実装の内容を考えた。

3. 要件定義を行う

次に要件定義にて、必要な機能を考えた。
また、必要な機能のページにて、どのような表示、ボタン操作等があるか列挙した。

次回

アプリケーションの立ち上げやDB設計を行う。

所感

要件定義をしっかりやっておくことで、今後の実装がスムーズになると思うので、時間はかかってしまうが毎回きちんとしたいと思った。

P.S.

Markdown記法の改行

Markdown記法でブログを書いてると、うまく改行されなかった場面があったので調べてみた。
改行する方法は以下の3つある。
①文末に半角スペースを2つつける
②1行空白の行を入れる
③brタグを使う
すべて同じ結果になるが、マークダウンを書く環境によって改行されないケースもあるので、3つの書き方を覚えておくのがよい。