【初学者向け】Gitのコマンドの使い方をよく忘れるから、纏めてみた
はじめに
Git: もう怖くないGit!チーム開発で必要なGitを完全マスター 山浦 清透を受講した時のメモがあったので、今の知識をもとに整理してみました。 これから新しいコマンドの使い方を覚えた時には、この記事に纏めていこうと思います。
- はじめに
- 1. 基本コマンド
- 2. git diff系
- 3. git log系
- 4. git rm系
- 5. git mv系
- 6. ワークツリーのファイル内の変更を取り消したい
- 7. addしたけど、その変更を取り消したい(=commit対象外にしたい)
- 8. git commitした後に、直前のコミットを取り消したい(git reset HEAD)
- 9. git pushした後に、直前のコミットを取り消したい(git revert)
- 10. 直前のコミットを修正したい(=今のステージの状態をもとに、コミットの内容を上書きしたい)
- 11. git remote系
- 12. git fetch系
- 13. git pull系
- 14. fetchとpull
- 15. リモートの詳細情報を表示する
- 16. リモート名を変更する、リモートを削除する
- 17. ブランチとは
- 18. HEADとは
- 19. branch関連のコマンド
- 20. merge系
- 21. コンフリクトとは
- 22. コンフリクトの事故が起きにくい運用ルール
- 23. ブランチを利用した開発の流れ
- 24. プルリクエストとは
- 25. rebaseで変更履歴を修正する
- 26. リベースとマージの違い
- 27. リベースとマージの使い分け
- 28. pullにはマージ型とリベース型がある
- 29. 複数のコミットをやり直す(git rebase)
- 30. Git管理対象外に置きたくないファイルをpushしてしまった時
- 31. git pushがrejectされた時の対処法
- その他Gitでよく使うコマンド
1. 基本コマンド
git init
git clone URL
- ローカルにリモートリポジトリのファイルをコピーする。
git add -A
git commit
- 変更を記録する(=コミット)。ステージの内容をスナップショットとしてリポジトリに記録する(変更、新規作成、削除、複数ファイルの変更・作成・削除)。
git commit -m 'メッセージ'
- コミットメッセージ(何を行なったか)をコマンドラインで直接指定できる。
git commit -v
- エディターを立ち上げて、「どのファイルにどんな変更をしたのか」エディター上で確認できる。結構オススメ。
git status
- 以下のような変更されたファイルを確認する。
- ワークツリーとステージの間で変更されたファイル(前回、ステージに追加してから変更したワークツリーのファイル)
- ステージとリポジトリの間で変更されたファイル(前回、コミットしてからステージに追加されたファイル)を確認できる。
- 以下のような変更されたファイルを確認する。
git remote add origin URL名
git push -u origin master(ブランチ名)
2. git diff系
git diff
- git addする前の変更差分を確認する。ワークツリーとステージの間の変更差分を確認する。
git diff ファイル名
- 特定のファイルの変更差分を見る。
git diff --staged
- ステージしたけど、まだコミットしてない変更差分を見る。git addした後の変更内容を確認する。
3. git log系
git log
- 今までの変更履歴(コミット)を確認する(最新のコミットから順に表示)。
git log --oneine
- 変更履歴を1行で表示。
git log -p ファイル名
- 指定したファイルの変更差分を表示する。
git log -n コミット数
- 表示するコミット数を制限(最新順で表示)。よく使う。
4. git rm系
git rm ファイル名
- ファイルの削除を記録する(削除された変更状態がステージに記録される)。
これは、ファイルごと削除するということ(=コミットした記録だけではなく、ワークツリー内のファイルも削除)。ワークツリーからもローカルリポジトリからも削除したい時に使う。
- ファイルの削除を記録する(削除された変更状態がステージに記録される)。
git rm -r ディレクトリ名
git rm --cached ファイル名
5. git mv系
git mv 旧ファイル 新ファイル
- ファイルの移動(=ファイル名の変更)を記録する。つまり、ワークツリーのファイル名が変更されて、かつ、ステージにも変更が反映される。
6. ワークツリーのファイル内の変更を取り消したい
git checkout -- ディレクトリ名
git checkout --.
- 全変更を取り消す。
7. add
したけど、その変更を取り消したい(=commit対象外にしたい)
更新内容自体は取り消さず、addしてインデックスに登録するのを取り消す。
git reset ファイル名
git reset
だけだと、ステージングにあるファイル全てを取り消す。
8. git commit
した後に、直前のコミットを取り消したい(git reset HEAD
)
1. git log
でコミット履歴を確認する。
$ gl -n 3 【 feature/19_meal_record_crud_exception 】 commit 4419fad760dd4e703559660195577047d88f60c5 (HEAD -> feature/19_meal_record_crud_exception) Author: ryota1116 <ryota@gmail.com> Date: Thu Aug 27 16:30:34 2020 +0900 [Add]MealRecordの各ページを修正 commit 2d14341fb814920c1072bd0a1e09678ad43abcef (origin/feature/19_meal_record_crud_exception) Author: ryota1116 <ryota@gmail.com> Date: Thu Aug 27 00:39:01 2020 +0900 [Fix]MealRecord検索フォームのjsファイルを修正 commit 14e7eaaf4b36535e32b342b33b7e54120f11f9bb Author: ryota1116 <ryota@gmail.com> Date: Thu Aug 27 00:17:06 2020 +0900 [Add]MealRecordフォームのi18nを追記
2. 取り消したいcommitをrevertする。
git reset HEAD^
で、HEADの1個前のコミットに戻る。git reset コミットID
でも可。HEAD^^^
で、HEADの3個前のコミットに戻る。
HEADの意味
HEAD -> aaa(ローカルブランチ名)
が現在のブランチの場所を指定(記憶)しており、その指定されているブランチが最新のコミットの位置を記憶している。origin/ブランチ名
はリモートにpush済。
9. git push
した後に、直前のコミットを取り消したい(git revert
)
git revert コミットID
revertするコミットを指定する感じ。
git logすると、commitとrevertのログが残ってるのが分かる。
- ただし、revertしたコミットのファイルがローカルからも消えちゃう(前のコミットに戻ったから)ので、「revertしたコミットの変更」をrevertしてあげれば、変更内容をローカルに残せる。以下のように。
git revert <revertしたコミットID> -n
で、revertしたコミットの変更を取り消す(直前のコミットIDの変更を削除したコミット
を取り消す感じかね。
10. 直前のコミットを修正したい(=今のステージの状態をもとに、コミットの内容を上書きしたい)
git commit --amend
- 例えば、ファイルの修正を忘れてた時に、ワークツリー内のファイルに変更を加え、
git add
→git commit --amend
を行う感じ。
- 例えば、ファイルの修正を忘れてた時に、ワークツリー内のファイルに変更を加え、
git commit --amendでaddし忘れたファイルを救済する - Qiita
注意点
リモートリポジトリにpushした後のコミットは絶対に
amend
で修正してはいけない!!!
pushした後にそのコミットを修正したければ、
git commit
でもう一度新しいコミットを作って修正すること。
11. git remote系
リモートリポジトリの情報を確認する
リモートリポジトリを複数登録する
メリット
- 複数のチームで作業するとき
- 自分のリモートを持ちたいとき
コマンド
git remote add リモート名 リモートURL
- リモート名(ショートカット)で、URLのリモートリポジトリを新規登録する。
12. git fetch系
リモートリポジトリから情報を取得する(フェッチ)
git fetch リモート名
git fetch origin
特徴など
13. git pull系
git pull リモート名 ブランチ名
「リモートから情報を取得し、マージまでを一度にやりたい」ときに使う。
- git fetchとgit mergeを同時に行っている。
14. fetchとpull
fetchを使うのが基本オススメみたい。
- pullは特殊な挙動を起こす。今自分がいるブランチに、pullしてきたブランチがマージされる。異なるブランチ同士が統合される恐れがある。ファイルがグチャグチャになる可能性があるということ。
自分が「マスターブランチにいて、何の変更もしていないときに限って」、pullで情報を取得するなどを行うべき。
- 安全なケースの時にだけpullを使うのが良さそう。
15. リモートの詳細情報を表示する
git remote show リモート名
- fetchとpushのURL、リモートブランチ、git pullの挙動、git pushの挙動などが表示される。
16. リモート名を変更する、リモートを削除する
git remote rename 旧リモート名 新リモート名
git remote rm リモート名
17. ブランチとは
- コミットを指すポインタのことで、並行して複数機能を開発するためにあるもの。
- ブランチは分岐して開発するためにあるもので、他の人の行った開発が、自分の開発には影響されないメリットを持つ(複数の機能の共同開発が可能となる)。
18. HEADとは
- 今自分が作業しているブランチを指し示したポインタのこと。
- このブランチとHEADの2つ(リポジトリ内に保存されている)により、最新のコミットがどれか分かる(順に
HEAD→ブランチ→コミット
と指している)
19. branch関連のコマンド
ブランチの新規作成
git branch ブランチ名
- ブランチを新規追加する。(ブランチの切り替えまでは行わない)
ブランチの表示
git branch
- 今あるブランチの一覧を表示。
git branch -a
- 全てのブランチを表示。リモートリポジトリも表示できる。
ブランチの切り替え
git checkout 既存ブランチ名
- ブランチを切り替える。(HEADが指し示すブランチを切り替えるということ)
git checkout -b 新ブランチ名
- ブランチを新規作成し、切り替えも行う。
ブランチ名を変更する
git branch -m 新ブランチ名
- 自分が現在作業しているブランチの名前を変更する。
リモートにpushした後にブランチ名を変更する
git branch -m 新ブランチ名 git push origin :旧ブランチ名 # リモート上にある旧名のブランチを削除 git push origin 新ブランチ名
ブランチを削除する
git branch -d ブランチ名
- masterにマージされていない変更が残っている場合、そのブランチは削除しないようになっている。安全。
git branch -D ブランチ名
- 強制削除する。慎重に使うこと。
20. merge系
マージ・・・他の人の変更内容を自分のブランチに取り込む作業のこと。
git merge ブランチ名
- 指定したブランチ名の変更内容を、自分が今いるブランチに取り込む。
git merge リモート名 ブランチ名
git merge origin master(リモートブランチ名)
- origin(=GitHubのこと)のmasterブランチの内容を、自分の作業ブランチに取り込む。
21. コンフリクトとは
- 複数人の人が、同じファイルの同じ行に対して、異なる編集を行った時に起こること。
- マージしたら、コンフリクトしてるよと言われ、Autoマージが失敗する。コンフリクトしても、落ち着いてファイルの内容をきれいに書き換えればOK。
22. コンフリクトの事故が起きにくい運用ルール
- 複数人で同じファイルを変更しない。
- pullやmergeする前に変更中の状態を無くしておく(
commit
やstash
(変更中のファイルを一時保管するコマンド)で変更中のファイルを無くしておく)。 - pullするときは、pullするブランチに移動してからpullする(同じ名前のブランチに移動してからpullしろってこと)。
23. ブランチを利用した開発の流れ
- masterブランチをリリース用ブランチとして使い、開発はトピックブランチを作成して進めるのが基本。
- masterブランチを常に最新のリリース状態に保っているから、最新のリリース内容がどんなものかmasterを見れば分かるようになっている!
- 何かバグが起きても、一つ前のマスターブランチのバージョンに戻せばいいだけ。
- masterで開発すると、最新のリリース状態がわからなくなるし、前のバージョンに切り戻すのが難しくなる。
- 開発するときは、最新のマスターからトピックごとにブランチを切って、そのトピックブランチで開発を行う。そして、開発が完了したらmasterにマージする。
24. プルリクエストとは
- 自分の変更したコードをリポジトリに取り込んでもらえるよう依頼する機能。バグを発生させない、コードの質を保つために、コードレビューを行ってもらう。
25. rebaseで変更履歴を修正する
git rebase ブランチ名
- 「ブランチの基点となるコミット」を別のコミットに移動する。コミットの履歴を一直線に綺麗に整えられる。
26. リベースとマージの違い
履歴が一直線なのか、枝分かれなのか
- rebase...作業の履歴を消したい場合
- 履歴をきれいに保つことが可能
- コンフリクトの解決が若干面倒(各コミットごとにコンフリクトが発生する)
- merge...作業の履歴を残したい場合
- コンフリクトの解決が比較的簡単(コンフリクトが一度しか発生しない)
- マージコミットがたくさんあると履歴が複雑化する
27. リベースとマージの使い分け
- プッシュしていないローカルの変更には、
リベース
を使う - プッシュした後は
マージ
を使う。コンフリクトしそうな時もマージを使う。
注意点
githubにプッシュしたコミットをリベースするのは絶対NG!!
git push -f
は絶対NG
28. pullにはマージ型とリベース型がある
- マージ型
- マージコミットが残るから、マージしたという記録を残したいときに使う。
- リベース型
- マージコミットが残らないから、Githubの内容を取得したいだけのときは以下のコマンドを使う。
git pull --rebase リモート名 ブランチ名
- マージコミットが残らないから、Githubの内容を取得したいだけのときは以下のコマンドを使う。
29. 複数のコミットをやり直す(git rebase)
git rebase -i コミット名
git rebase -i HEAD~3
- 直前3つのコミットをやり直す
30. Git管理対象外に置きたくないファイルをpushしてしまった時
秘匿情報の入ったファイル、アプリケーションとは関係のないスクショなどを.gitignore
の中に指定するのを忘れ、pushしちゃった時に、そのファイルをGit管理対象外にする。
git rm --cached ファイル名
このコマンドで対象にされたファイルは、.gitignore
が適用されるようになる。
git rm --cached ファイル名
とすると、ローカルからファイルが一旦消えるため、どこかにバックアップを取っておく。
push→pullしたあと、ファイルがdeletedになるから、ローカルにコピーして書き直せばおk。
31. git push
がrejectされた時の対処法
ローカルでコミットした後に、Githubへpushしようとすると以下のようなエラーが表示されることがある。
~/workspace/app/cat_meow_miaow $ git push --set-upstream origin master 【 master 】 To https://github.com/ryota1116/cat_meow_miaow.git ! [rejected] master -> master (non-fast-forward) error: failed to push some refs to 'https://github.com/ryota1116/cat_meow_miaow.git' hint: Updates were rejected because the tip of your current branch is behind hint: its remote counterpart. Integrate the remote changes (e.g. hint: 'git pull ...') before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details.
これは自分がpushするまでの間に、他の人が同じブランチ(以下の例ではmasterブランチ)にpushしているなどリモートの内容が変更されている場合に表示されるエラー。解決方法としては、リモートの最新の内容をローカルに反映させてあげる必要がある。
git pull リモートブランチ名 作業ブランチ名
としてあげればいいので、今回の例でいけば、git pull origin master
を実行する。
もしくは、git pull --rebase リモートブランチ名 作業ブランチ名
としてあげると、remoteの変更をpullした上で、その後にローカル上の変更をマージしてくれるので、コッチのが手っ取り早くはある。
$ git pull --rebase origin master 【 master 】 From https://github.com/ryota1116/cat_meow_miaow * branch master -> FETCH_HEAD First, rewinding head to replay your work on top of it... warning: unable to rmdir 'sound': Directory not empty Applying: [Add]キー入力で音声出力 Using index info to reconstruct a base tree... Falling back to patching base and 3-way merge...
これでpushできるようになったはず。
その他Gitでよく使うコマンド
git stash
git stash -u
git stash apply
git stash pop
git reset -soft HEAD^
git reset -soft HEAD^^
git reset -soft HEAD2^
git reset -hard HEAD2^
(危険)git merge --abort
【Ruby】Date型で色んなメソッドを試してみる
今日、昨日、○日前、○日後とか
# 今日 [1] pry(main)> Date.today => Sat, 22 Aug 2020 [6] pry(main)> Date.current => Sat, 22 Aug 2020 # 昨日 [7] pry(main)> Date.current.yesterday => Fri, 21 Aug 2020 # 昨日(1日前) [8] pry(main)> Date.current.ago(1.day) => Fri, 21 Aug 2020 00:00:00 JST +09:00 # 3日前 [9] pry(main)> Date.current.ago(3.day) => Wed, 19 Aug 2020 00:00:00 JST +09:00 # 10日前 [8] pry(main)> Date.today.prev_day(10) => Mon, 17 Aug 2020 # 10日語 [7] pry(main)> Date.today.next_day(10) => Sun, 06 Sep 2020 # 2ヶ月後 [9] pry(main)> Date.today.next_month(2) => Tue, 27 Oct 2020
日・週・月などを丸々取得
# 今日24時間丸々 [16] pry(main)> Date.current.all_day => Sat, 22 Aug 2020 00:00:00 JST +09:00..Sat, 22 Aug 2020 23:59:59 JST +09:00 # 今週丸々 [17] pry(main)> Date.current.all_week => Mon, 17 Aug 2020..Sun, 23 Aug 2020 [18] pry(main)> Date.current.all_month => Sat, 01 Aug 2020..Mon, 31 Aug 2020 [19] pry(main)> Date.current.all_year => Wed, 01 Jan 2020..Thu, 31 Dec 2020
日・週・月などの始まり・終わり
# 今日の0時 [21] pry(main)> Date.current.beginning_of_day => Sat, 22 Aug 2020 00:00:00 JST +09:00 # 今週最初の日(月曜日) [13] pry(main)> Date.current.beginning_of_week => Mon, 17 Aug 2020 # 今週最後の日(日曜日) [14] pry(main)> Date.current.end_of_week => Sun, 23 Aug 2020 # 今月最後の日 [15] pry(main)> Date.current.end_of_month => Mon, 31 Aug 2020 # 今年最後の日 [20] pry(main)> Date.current.end_of_year => Thu, 31 Dec 2020
指定したオブジェクトが、どんなメソッド等を使用できるのか確認する
ある型を持つオブジェクト(今回で言えばDate型)が、どのようなメソッドを使用できるのか確認する癖は付けておいた方がいいと思う。
[16] pry(main)> today = Date.today => Thu, 27 Aug 2020 [18] pry(main)> today.class => Date [17] pry(main)> ls today ActiveSupport::ToJsonWithActiveSupportEncoder#methods: to_json ActiveSupport::Dependencies::ZeitwerkIntegration::RequireDependency#methods: require_dependency Comparable#methods: < <= == > >= between? clamp DateAndTime::Zones#methods: in_time_zone DateAndTime::Calculations#methods: after? all_year at_end_of_month beginning_of_month days_since end_of_year last_weekday next_occurring on_weekend? prev_weekday weeks_since all_day at_beginning_of_month at_end_of_quarter beginning_of_quarter days_to_week_start future? last_year next_quarter past? sunday years_ago all_month at_beginning_of_quarter at_end_of_week beginning_of_week end_of_month last_month monday next_week prev_occurring today? years_since all_quarter at_beginning_of_week at_end_of_year beginning_of_year end_of_quarter last_quarter months_ago next_weekday prev_quarter tomorrow yesterday all_week at_beginning_of_year before? days_ago end_of_week last_week months_since on_weekday? prev_week weeks_ago Date#methods: + ajd at_noon cwyear gregorian jd midday new_start prev_month step to_s - amjd beginning_of_day day gregorian? jisx0301 middle_of_day next prev_year strftime to_time << as_json blank? day_fraction hash julian midnight next_day readable_inspect succ tuesday? <=> asctime change default_inspect httpdate julian? minus_with_duration next_month rfc2822 sunday? upto === at_beginning_of_day compare_with_coercion downto in ld minus_without_duration next_year rfc3339 thursday? wday >> at_end_of_day compare_without_coercion end_of_day infinite? leap? mjd noon rfc822 to_date wednesday? acts_like_date? at_midday ctime england inspect marshal_dump mon plus_with_duration saturday? to_datetime xmlschema advance at_middle_of_day cwday eql? iso8601 marshal_load monday? plus_without_duration since to_default_s yday ago at_midnight cweek friday? italy mday month prev_day start to_formatted_s year
参照記事
Rails6にSemanticUIを導入
Rails6でのSemantic UIの導入
BootstrapのフレームワークであるSemantic UIをRails6で使ってみたので、以下に導入方法を記しておきます。
以下の記事もよければ参考にしてください。
【Rails】Semantic UIを使って動的にフラッシュメッセージを表示する方法 - Qiita
前提
Webpackerでの導入方法が分からなかったので、従来のassetsフォルダでの導入にしました。。。
Webpackerでの導入方法が分かり次第、更新したいと思います。
追記
公式のisuueを追ったところ、semantic-ui-sassはwebpackerで導入する方法が見当たらなかった。
How to add semantic-ui-sass on Rails 6 · Issue #144 · doabit/semantic-ui-sass · GitHub
導入方法
- Gemをインストールする。
(Gemfile) gem 'semantic-ui-sass'
- マニフェストファイルの編集。
(app/assets/stylesheets/application.scss) @import "semantic-ui";
(app/assets/javascript/application.js) // Loads all Semantic javascripts // = require semantic-ui
500エラーが表示されるので、エラーメッセージを確認。
ActionView::Template::Error - Asset `application.js` was not declared to be precompiled in production. Declare links to your assets in `app/assets/config/manifest.js`. //= link application.js and restart your server: app/views/layouts/application.html.slim:11:in `view template'
app/assets/config/manifest.js
に//= link application.js
を追記。
(app/assets/config/manifest.js) //= link_tree ../images //= link_directory ../stylesheets .css //= link application.js
これだけでSemantic UIの記述を反映できる。
Rails6にjQueryを導入
Rails6でjQueryを導入する方法
yarn add jquery
package.json
とyarn.lock
を確認すると、jQueryが追加されていることが分かる。
(package.json) { "name": "zero_calorie", "private": true, "dependencies": { "@rails/actioncable": "^6.0.0", "@rails/activestorage": "^6.0.0", "@rails/ujs": "^6.0.0", "@rails/webpacker": "4.2.2", "jquery": "^3.5.1", "turbolinks": "^5.2.0" }, "version": "0.1.0", "devDependencies": { "webpack-dev-server": "^3.11.0" } }
(yarn.lock) jquery@^3.5.1: version "3.5.1" resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.5.1.tgz#d7b4d08e1bfdb86ad2f1a3d039ea17304717abb5" integrity sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg==
(config/webpack/environment.js) const { environment } = require('@rails/webpacker') module.exports = environment
以下のように変更
(config/webpack/environment.js) const { environment } = require('@rails/webpacker') const webpack = require('webpack') environment.plugins.prepend('Provide', new webpack.ProvidePlugin({ $: 'jquery/src/jquery', jQuery: 'jquery/src/jquery' }) ) module.exports = environment
JS、jQueryのファイルを読み込む
(app/javascript/packs/application.js) require("@rails/ujs").start() require("turbolinks").start() require("@rails/activestorage").start() require("channels") // 追加 require("jquery") require("jquery/submit_food_image")
htmlが記述されたslimファイル
h1 id="red" | 食事記録の一覧 h2 食事記録
jsファイルを作成。これでJS、JQueryで記述した内容が反映される。
(app/javascript/jquery/submit_food_image.js) $(function () { $(document).ready(function(){ $("#red").css("color", "red"); }); });
slimで直書きVer.
h1 id="red" | 食事記録の一覧 h2 食事記録 javascript: $(function () { $(document).ready(function(){ $("#red").css("color", "red"); }); });
参照サイト
【Rails】マイグレーションファイルをmigrateする前に戻す方法(その他マイグレーション関連のコマンド)
be rails db:migrate:status
でmigrateの状況を確認。
up
になっているファイルがmigrateされている。
$ be rails db:migrate:status database: zero_calorie_development Status Migration ID Migration Name -------------------------------------------------- up 20200802075924 Create meal records up 20200802080924 Create active storage tablesactive storage up 20200804123950 Create foods
be rails db:rollback STEP=3
で3つのファイル(最新順)をmigrate前に戻す。
$ be rails db:rollback STEP=3 == 20200804123950 CreateFoods: reverting ====================================== -- drop_table(:foods) -> 0.0920s == 20200804123950 CreateFoods: reverted (0.0986s) ============================= == 20200802080924 CreateActiveStorageTables: reverting ======================== -- drop_table(:active_storage_attachments, {}) -> 0.1429s -- drop_table(:active_storage_blobs, {}) -> 0.0940s == 20200802080924 CreateActiveStorageTables: reverted (0.2376s) =============== == 20200802075924 CreateMealRecords: reverting ================================ -- drop_table(:meal_records) -> 0.0528s == 20200802075924 CreateMealRecords: reverted (0.0530s) ======================= Model files unchanged.
down
になっているファイルは、migrateされる前の状態に戻ったということ。
down状態のファイルは直接編集おk。
(ただし、「新機能を実装するためにFoodテーブルと他のテーブルにアソシエーションを組みたい」といった場合、rollbackするのではなく新しくマイグレーションファイルを作成してあげればよい。マイグレーションファイルは歴史の積み重ね的なやつだから時系列で残してあげた方がよいと思われる)
$ be rails db:migrate:status database: zero_calorie_development Status Migration ID Migration Name -------------------------------------------------- down 20200802075924 Create meal records down 20200802080924 Create active storage tablesactive storage down 20200804123950 Create foods
$ be rails db:migrate == 20200802075924 CreateMealRecords: migrating ================================ -- create_table(:meal_records) /Users/funesakisuke/workspace/app/zero_calorie/vendor/bundle/ruby/2.7.0/gems/migration_comments-0.4.1/lib/migration_comments/active_record/connection_adapters/mysql2_adapter.rb:39: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call /Users/funesakisuke/workspace/app/zero_calorie/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.2/lib/active_record/connection_adapters/mysql/schema_statements.rb:80: warning: The called method `create_table' is defined here /Users/funesakisuke/workspace/app/zero_calorie/vendor/bundle/ruby/2.7.0/gems/migration_comments-0.4.1/lib/migration_comments/active_record/connection_adapters/table_definition.rb:10: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call /Users/funesakisuke/workspace/app/zero_calorie/vendor/bundle/ruby/2.7.0/gems/activerecord-6.0.3.2/lib/active_record/connection_adapters/abstract/schema_definitions.rb:364: warning: The called method `column' is defined here -> 0.0480s == 20200802075924 CreateMealRecords: migrated (0.0481s) ======================= == 20200802080924 CreateActiveStorageTables: migrating ======================== -- create_table(:active_storage_blobs, {}) -> 0.0524s -- create_table(:active_storage_attachments, {}) -> 0.0477s == 20200802080924 CreateActiveStorageTables: migrated (0.1003s) =============== == 20200804123950 CreateFoods: migrating ====================================== -- create_table(:foods) -> 0.0516s == 20200804123950 CreateFoods: migrated (0.0517s) ============================= Annotated (3): app/models/meal_record.rb, spec/models/meal_record_spec.rb, spec/factories/meal_records.rb
$ be rails db:migrate:status database: zero_calorie_development Status Migration ID Migration Name -------------------------------------------------- up 20200802075924 Create meal records up 20200802080924 Create active storage tablesactive storage up 20200804123950 Create foods
その他コマンド
- 全てのテーブルをドロップして、全てのmigrationを実行してテーブルの再作成を行う。
be rails db:migrate:reset
情報収集のやり方と好きなメディアサービスやブログを纏めておく
はじめに
Feedlyを使って効率的に情報収集しよう
私は10個くらいのメディアを使って情報収集しているのですが、全メディアのサイトを訪問しているようでは、時間がいくらあっても足りません。
そこで色んなサイトの記事を1つのプラットフォームで一元管理してくれるFeedlyというサービスを使っています。
Feedlyのページを見るだけで、各サイトの欲しい内容は大体漏れなくキャッチアップできますし、情報収集のハードルも下がります。控えめに言ってめっちゃオススメ。
この方の動画見たら使い方分かると思います www.youtube.com
好きなメディアやブログ
以下にザックリ纏めてみました。
はてなブログ
安定のはてぶ b.hatena.ne.jp
TechCrunch
スタートアップ企業の紹介やインターネットの新しいプロダクトのレビュー、そして業界の重要なニュースを扱うテクノロジーメディア jp.techcrunch.com
業界カオスマップもよく見ている jp.techcrunch.com
Monthly Pitch
創業期の企業家向けのピッチイベント monthly-pitch.com
スタートアップタイムズ
スタートアップのインタビュー記事 これめっちゃ面白いのでオススメ startuptimes.jp
新R25
これからの時代を生きる若者の仕事や人生のバイブル的存在らしい。 読んでてワクワクする。 r25.jp
News Picks
学生時代から読んでる一番お世話になってるメディアかも。 難しいテーマをイラスト付きで解説してくれるまとめコラムみたいなのが面白い。 newspicks.com
CodeZine
プログラミングに役立つソースコードと解説記事が満載な開発者のための実装系Webマガジン codezine.jp
TechFeed
"地上最強"のエンジニア向け情報サービスらしい
TechFeed Pro - "地上最強"のエンジニア向け情報サービス
Menthas
プログラマ向けのニュースサイト menthas.com
エンジニア採用・育成・組織づくりラボ by Findy
Findy(ファインディ)Inc.が運営するCTO等のエンジニアマネジメント層や人事・採用担当者向けのメディア
あんまり見ないけど一応。
blog.findy.us
クックパッド開発者ブログ
食べチョク開発者ブログ
【Rails】RailsでAPIを叩く基本編
APIの特徴などを軽く抜粋(dysonさんメモ)
APIはインターフェイス=エンドポイントと思っておk
→要はURL(http://localhost3000/users/1など)決められたインターフェースに適合するようにリクエストを送ると、それに応じたレスポンスが返ってくる
外部のAPIを使う
→あるパラメータをあるエンドポイントに送ると、あるレスポンスが返ってくる。データベースに情報を持っている
→それを皆に使ってもらえるようにAPIを作る決められたインターフェースに適合するように=こういう条件を満たすように
JSON形式のデータを返すことが主流
render json: hoge
jsonのserializerとは?
jsonを生成する仕組みのこと。
→この生成したJSONのデータをレスポンスとして返す。
ActiveRecordは ActiveModel::Serializationをinclude している。なので、以下のようにrender json
と、そのまま記述できる。
module Api module V1 class ArticlesController < BaseController def index articles = Article.all render json: articles end end end end
今回実装してみる要件
fast_jsonapiというserializerを使って、 記事一覧のjsonレスポンスを返す。
- Articleモデル。Userモデルと一対多の関係。
(app/models/article.rb) class Article < ApplicationRecord belongs_to :user has_many :comments, dependent: :destroy has_one_attached :eye_catch enum status: { draft: 0, in_review: 10, published: 20, archived: 30 } end
- Articleモデルのシリアライザーを作る
$ be rails g serializer Article title contents status Running via Spring preloader in process 21798 create app/serializers/article_serializer.rb
- シリアライザーの設定
(app/serializers/article_serializer.rb) class ArticleSerializer include FastJsonapi::ObjectSerializer attributes :title, :contents, :status belongs_to :user end
(app/controllers/api/v1/articles_controller.rb) # frozen_string_literal: true module Api module V1 class ArticlesController < BaseController def index articles = Article.all json_string = ArticleSerializer.new(articles).serialized_json # 上と同じ # json_string = ArticleSerializer.new(articles).serializable_hash.to_json render json: json_string end end end end
PostmanでAPIを叩いてみると、ちゃんとデータが取れた。
{ "data": [ { "id": "1", "type": "article", "attributes": { "title": "title-1", "contents": "contents-1", "status": "draft" }, "relationships": { "user": { "data": { "id": "1", "type": "user" } } } }, { "id": "2", "type": "article", "attributes": { "title": "title-2", "contents": "contents-2", "status": "draft" }, "relationships": { "user": { "data": { "id": "2", "type": "user" } } } }, ... ...... ........
Userログインを叩くとこんな感じ
関連モデルのデータを返す
ArticleSerializer.new(@article).serialized_json
の場合
def show # options = { include: [:user, :'user.name', :'user.email'] } json_string = ArticleSerializer.new(@article).serialized_json render json: json_string end
以下のようなJSONレスポンスが返ってくる。記事に関連付いたユーザーのidも返ってくる。
{ "data": { "id": "1", "type": "article", "attributes": { "title": "title-1", "contents": "contents-1", "status": "draft" }, "relationships": { "user": { "data": { "id": "1", "type": "user" } } } } }
options = { include: %i[user user.name user.email] }
とArticleSerializer.new(@article, options).serialized_json
の場合
def show # options = { include: [:user, :'user.name', :'user.email'] } options = { include: %i[user user.name user.email] } json_string = ArticleSerializer.new(@article, options).serialized_json render json: json_string end
記事に関連付いたユーザーのレコードも返ってくる。
"data": { "id": "1", "type": "article", "attributes": { "title": "title-1", "contents": "contents-1", "status": "draft" }, "relationships": { "user": { "data": { "id": "1", "type": "user" } } } }, "included": [ { "id": "1", "type": "user", "attributes": { "name": "user-1", "email": "user-1@example.com" }, "relationships": { "articles": { "data": [ { "id": "1", "type": "article" } ] } } } ] }
リクエストスペックの書き方も
require 'rails_helper' RSpec.describe "Api::V1::Articles", type: :request do let!(:user) { create(:user) } describe "GET /api/v1/article/:id" do let!(:article) { create(:article, user: user) } it "掲示板詳細を返す" do get api_v1_article_path(article.id), headers: { 'CONTENT_TYPE': 'application/json', 'ACCEPT': 'application/json' } json = JSON.parse(response.body) expect(response).to be_successful expect(response).to have_http_status(200) expect(json["data"]["id"].to_i).to eq(article.id) # to_iでid='1'という文字列を数値に変換する # digを使う # expect(json["data"]["relationships"]["user"]["data"]["id"].to_i).to eq(article.user_id) expect((json.dig("data", "relationships", "user", "data", "id")).to_i).to eq(article.user_id) end end
【Rails/Rspec】リクエストスペックでAPIをテストする際に、よくやること
リクエストスペックの特徴
- HTTP 動詞に対応するメソッド(get 、post 、delete 、 patch)を使う。
- capybaraは使わない。
- HTTPのレスポンスのステータスコードと実際のデータを含んだレスポンスボディを返す
200: OK - リクエストは成功し、レスポンスとともに要求に応じた情報が返される。 401: Unauthorized - 認証失敗。認証が必要である。 403: Forbidden - 禁止されている。リソースにアクセスすることを拒否された。 404: Not Found - 未検出。リソースが見つからなかった。
リクエストスペックでよく使うヤツ
JSON.parse
与えられた JSON 形式の文字列を Ruby オブジェクトに変換して返す。
→JSON形式の文字列からRubyのHashへ変換することで、WebAPIで取得したJSONデータをRubyで使える様にするリクエストヘッダーをセットしておく。
→ヘッダ情報がないとテストが通らないことがある。
get api_v1_articles_path, headers: { 'CONTENT_TYPE': 'application/json', 'ACCEPT': 'application/json' }
(spec/requests/api/v1/articles_spec.rb) require 'rails_helper' RSpec.describe "Api::V1::Articles", type: :request do describe "GET /api/v1/articles" do it "掲示板一覧を返す" do create_list(:article, 10, user: user) get api_v1_articles_path, headers: { 'CONTENT_TYPE': 'application/json', 'ACCEPT': 'application/json' } // JSON.parse(body)でもいけたけど、response.bodyにしておく json = JSON.parse(response.body) expect(response).to have_http_status(200) expect(json["data"].count).to eq(10) end end end
letを使って、headers情報を格納しておく。
let(:headers) do { 'Content-Type' => 'application/json', 'Accept' => 'application/json' } end
letで数字を変数(numとか)に入れておくのもアリ
RSpec.describe 'Api::V1::Articles', type: :request do describe 'GET /articles' do let(:article_num) { 10 } before do user = create(:user) create_list(:article, article_num, user: user) end it 'returns fincle articles in json format' do get api_v1_articles_path, headers: { CONTENT_TYPE: 'application/json', ACCEPT: 'application/json', } expect(JSON.parse(body)['data'].count).to eq(article_num) expect(response).to be_successful expect(response).to have_http_status(:ok) end end end
上記テストの、JSON.parse(response.body)["data"]の結果
JSON.parse(response.body)["data"] => [{"id"=>"1", "type"=>"article", "attributes"=>{"title"=>"title-1", "contents"=>"contents-1", "status"=>"draft"}, "relationships"=>{"user"=>{"data"=>{"id"=>"1", "type"=>"user"}}}}, {"id"=>"2", "type"=>"article", "attributes"=>{"title"=>"title-2", "contents"=>"contents-2", "status"=>"draft"}, "relationships"=>{"user"=>{"data"=>{"id"=>"2", "type"=>"user"}}}}, {"id"=>"3", "type"=>"article", "attributes"=>{"title"=>"title-3", "contents"=>"contents-3", "status"=>"draft"}, "relationships"=>{"user"=>{"data"=>{"id"=>"3", "type"=>"user"}}}}, {"id"=>"4", "type"=>"article", "attributes"=>{"title"=>"title-4", "contents"=>"contents-4", "status"=>"draft"}, "relationships"=>{"user"=>{"data"=>{"id"=>"4", "type"=>"user"}}}}, {"id"=>"5", "type"=>"article", "attributes"=>{"title"=>"title-5", "contents"=>"contents-5", "status"=>"draft"}, "relationships"=>{"user"=>{"data"=>{"id"=>"5", "type"=>"user"}}}}, {"id"=>"6", "type"=>"article", "attributes"=>{"title"=>"title-6", "contents"=>"contents-6", "status"=>"draft"}, "relationships"=>{"user"=>{"data"=>{"id"=>"6", "type"=>"user"}}}}, {"id"=>"7", "type"=>"article", "attributes"=>{"title"=>"title-7", "contents"=>"contents-7", "status"=>"draft"}, "relationships"=>{"user"=>{"data"=>{"id"=>"7", "type"=>"user"}}}}, {"id"=>"8", "type"=>"article", "attributes"=>{"title"=>"title-8", "contents"=>"contents-8", "status"=>"draft"}, "relationships"=>{"user"=>{"data"=>{"id"=>"8", "type"=>"user"}}}}, {"id"=>"9", "type"=>"article", "attributes"=>{"title"=>"title-9", "contents"=>"contents-9", "status"=>"draft"}, "relationships"=>{"user"=>{"data"=>{"id"=>"9", "type"=>"user"}}}}, {"id"=>"10", "type"=>"article", "attributes"=>{"title"=>"title-10", "contents"=>"contents-10", "status"=>"draft"}, "relationships"=>{"user"=>{"data"=>{"id"=>"10", "type"=>"user"}}}}]
記事詳細のレスポンスに
JSON.parse
[7] JSON.parse(body) => {"data"=>{"id"=>"1", "type"=>"article", "attributes"=>{"title"=>"title-11", "contents"=>"contents-11", "status"=>"draft"}, "relationships"=>{"user"=>{"data"=>{"id"=>"2", "type"=>"user"}}}}} [8] JSON.parse(body)["data"] => {"id"=>"1", "type"=>"article", "attributes"=>{"title"=>"title-11", "contents"=>"contents-11", "status"=>"draft"}, "relationships"=>{"user"=>{"data"=>{"id"=>"2", "type"=>"user"}}}} [9] JSON.parse(body)["data"]["id"] => "1" [10] JSON.parse(body)["data"]["attributes"] => {"title"=>"title-11", "contents"=>"contents-11", "status"=>"draft"} [11] JSON.parse(body)["data"]["attributes"]["title"] => "title-11" レスポンスボディ?の数 [12] JSON.parse(body).count => 1 relationship [14] JSON.parse(body)["data"]["relationships"] => {"user"=>{"data"=>{"id"=>"2", "type"=>"user"}}} ステータスコード [3] response.status => 200
attributes_for
POSTメソッドで、 - ファクトリからテスト用の属性値をハッシュとして作成する。複数のパラメータを送信する場合に、個々にパラメータ名を付けるのではなく、キーと値を組み合わせたハッシュを作成してくれる。 - buildならモデルオブジェクトを作成する。
https://qiita.com/_kotaro/items/adbc355bfb550b8b2150
FactoryBotのデータ
(spec/factories/users.rb) FactoryBot.define do factory :user do sequence(:name) { |n| "user-#{n}" } sequence(:email) { |n| "user-#{n}@example.com" } password { 'password' } end end
- attributes_for
let!(:user_attributes) { attributes_for(:user) } => {:name=>"user-1", :email=>"user-1@example.com", :password=>"password"}
- build
let!(:user_attributes) { build(:user) } => #<User:0x00007fcf5a68cff0 id: nil, name: "user-1", email: "user-1@example.com", crypted_password: nil, salt: nil, created_at: nil, updated_at: nil>
- create
let!(:user_attributes) { create(:user) } => #<User:0x00007fb222ebcf18 id: 1, name: "user-1", email: "user-1@example.com", crypted_password: "$2a$04$rslb/9FwCJVJFYmR.LeLR.8JjYOt2kEYCh8d2F5E1JJGRJ1lZ/BiS", salt: "hoCH88wcyx3PFVqxduem", created_at: Sun, 26 Jul 2020 02:15:36 UTC +00:00, updated_at: Sun, 26 Jul 2020 02:15:36 UTC +00:00>
to_json
RubyのHash形式のデータを、JSON形式の文字列に変換してくれる。
[1] user_attributes => {:name=>"user-1", :email=>"user-1@example.com", :password=>"password"} [2] user_attributes.to_json => "{\"name\":\"user-1\",\"email\":\"user-1@example.com\",\"password\":\"password\"}"
【超Vue.js】フィルターとミックスイン【セクション11 】
※ セクション8~10はわざわざ纏める必要あるか微妙だったので、一旦パス。
144. フィルターを使用して、一般的なテキストフォーマットを作成する
フィルター…テキストをフォーマットするためのもの。文字を全部大文字にするみたいな。
今まではcomputedでやっていた。
→computedだと、dataの各プロパティごとに、dataの各プロパティごとに大文字にする設定を記述必要がある。
→大文字にフォーマットするプロパティをdata毎に作ってあげる必要がある。
main.jsに書く
1引数にフィルター名 2引数に関数→関数に必ず引数を取る→引数がフォーマットしたい値→フォーマットした値をreturnする dataのプロパティ名 パイプ記号 フィルター名
(main.js) Vue.filter("uppercase", function(value) { return value.toUpperCase(); }
{{ data名 | uppercase }}
145. コンポーネントのオプション内でローカルフィルタを定義する
ローカル登録
filters: { フィルター名(value) { return value.toLower
146. 複数のフィルタ関数を連結させる
フィルターの特徴
- フィルタを連結できる
→パイプ記号で連結させる
→左側のフィルターから実行される
147. フィルターでthisが使えないことに注意する
フィルター内ではthisは使えない
thisでアクセスしたいなら、computed、メソッドを使う。
148. computedとフィルターのキャッシュに対する違いを理解する
computed...リアクティブな依存関係に基づいてキャッシュする
→必要な時だけ変わるフィルタ...そのような機能はない。メソッドと同じで再描画される
→頻繁に再描画される場合はフィルタを使うのを避けよう。
149. 共有できるコードを全てミックスインにする
ミックスインとは
export default, data, filters, directivesなどのoptionを、複数のコンポーネントで共有できる。コードの再利用。
150. 実際にミックスインを作って、オプションをコンポーネント間で共有する
共有化したいオプションを、オブジェクトとして別ファイル(js)に移し、そのファイルを使いたいコンポーネントファイルでimportする。
→mixinsは配列にして、importしたモノを指定する。
151. オプションが被ったときに、どのようにミックスインがマージされるのか
mixinファイルとコンポーネントファイルでオプション名が被った場合
→全てのオプションにおいてコンポーネントが優先される
※ created, mountedなどライフサイクルフックは別
→mixinのライフサイクルが先に実行される。その後にcomponentのふっくが実行される。
152. グローバルミックスインを作成する
グローバルミックスインのオプションは、全てのVueインスタンスに自動で適用されてしまう!
globalが最初に実行される。使う時は要注意。普通は使わない。
【記録】良記事とかをまとめておく
マインド
質問・学習などについて
IT業界に入ってからの一番最初の勉強法(もしくはプログラミングの勉強について新人さんに伝えたいこと) - give IT a try
「未経験文系から3ヶ月でデータサイエンティストになって一発逆転」はここで終わり (2020/7/31 更新) - todo-mentor’s diary
各社研修
DeNA1年目エンジニアが語る、社会人になった僕らの変化 -学生時代の自分に言いたいこと- · DeNA Engineers' Blog
2020年のエンジニア新人研修の講義資料を公開しました - Cybozu Inside Out | サイボウズエンジニアのブログ
リクルートテクノロジーズ エンジニアコース新人研修の内容を公開します!(2020年度版) | リクルートテクノロジーズ メンバーズブログ
技術基礎研修「クックパッドを支える仕組み」 / Introduction to the Internet - Speaker Deck
検索系
キャリア
効率系
英語
個人開発
デザイン
Mac
Linux
Vim
Git
GitHubのREADMEをサクッと高品質で書けるサービス作ってみました。 - Qiita
HTTP
ネットワーク
データベース
Ruby
Rails
Rails開発者が採用面接で聞かれる想定Q&A 53問(翻訳)|TechRacho(テックラッチョ)〜エンジニアの「?」を「!」に〜|BPS株式会社
Rails 5.1〜6: 'form_with' APIドキュメント完全翻訳|TechRacho(テックラッチョ)〜エンジニアの「?」を「!」に〜|BPS株式会社
肥大化したActiveRecordモデルをリファクタリングする7つの方法(翻訳)|TechRacho(テックラッチョ)〜エンジニアの「?」を「!」に〜|BPS株式会社
Rails アンチパターン - ファットコントローラー(Fat Controller) - blog.waterlow.work
GitHub - DaichiSaito/rails_good_reference: Railsおよびその周辺知識に関する参考記事をまとめる
アウトプットのネタに困ったらこれ!?Ruby初心者向けのプログラミング問題を集めてみた(全10問) - give IT a try
3年以上かけて培ったRails開発のコツ集大成(翻訳)|TechRacho(テックラッチョ)〜エンジニアの「?」を「!」に〜|BPS株式会社
Railsのルーティングを極める(前編)|TechRacho(テックラッチョ)〜エンジニアの「?」を「!」に〜|BPS株式会社
Railsのルーティングを極める (後編)|TechRacho(テックラッチョ)〜エンジニアの「?」を「!」に〜|BPS株式会社