RSpec
今日は、「コピペせず、1回はする」を試してみた。
結構頭に入る。
RSpec
「Spec」 = テストコード
「Ruby」 + 「Spec」 = Rubyのテストコード
なぜ Spec = テストコード?
≪chatGPT先生≫
「spec」という用語は、「specification」(仕様)の略称として使われることがあります。テストコードは、プログラムの機能や振る舞いが正しく動作するかどうかを確認するために書かれるものであり、そのプログラムの仕様に基づいて動作するべきものです。そのため、テストコードはプログラムの仕様を具体的に表現する一部と考えることができます。このような背景から、「spec」という用語はテストコードやテストスイートを指すのに使用されることがあります。
チェック機能と言いながら、それが自体が仕様を表現しているということらしい。(へー)
RSpecはフレームワーク?
「Rubyの中で、もう一つのフレームワークが動いている」ということを意識すると理解しやすい(らしい)
メソッド関係
spec/rails_helper.rb
- Railsのテストをするときの共通の設定を書いておくファイル。
- テストファイルは、
require 'rails_helper'
でこのファイルを読みにいく。
describe
メソッド- テストコードのグループ分け
- describe: 記述する
- 入れ子(nest)にして、機能ごとに記述。
it
メソッドdescribe
と同じでグループを作る。- その一つ一つを
example
と呼ぶ。(個別にテストする'事例'的な?)
bundle exec
% bundle exec rspec spec/models/user_spec.rb
valid?
メソッド- テストコード内の任意のタイミングで
validates
を実行できるメソッド。true
かfalse
を返すfalse
の場合はエラーメッセージを生成する
(valid?
があって初めてerrors
メソッドが使える)
- テストコード内の任意のタイミングで
expectation
: 期待、想定- 想定通り動くかの確認 = '想定する挙動' + 'アプリの挙動'
- 雛形
expect().to matcher()
matcher
=include
(包含する) oreq
(=equal: 等しい)expect
の引数と'match'してるか確認できる
errors
メソッド- エラー内容を確認できる。
full_messages
= ’エラーメッセージ'を'配列'として返す
#user = User.new(nickname: '') [4] pry(main)> user.errors => <ActiveModel::Errors [#<ActiveModel::Error attribute=nickname, type=blank, options={}>]>
#user = User.new(nickname: '') [6] pry(main)> user.errors.full_messages => ["Nickname can't be blank"]
英単語
factory: 作る(facio)場所(-orium) -> 工場、製造所、製作所
- factor: factus(作った)+-tor(~するもの) -> 要因、因数
- fact: 実際にした(factus)こと -> 事実、真相、現実
- affect: ~へ(ad-)作り出す(facio)、~へ作用する -> に作用する、を感動させる
- effect: 作り(fectus)出した(ex-)、作り出した結果 -> 効果、結果、影響
- defect: 不完全に(de-)作られた(fectus)こと -> 欠陥、短所、欠点
instance: 上に(in-)立っ(sto)ている(-ans)こと(-ia)、近くに存在すること -> 例、場合、出来事
- substance: 下に(sub-)立っ(sto)ていること(-ance)、根っこにあること -> 物質、重要性、実質
- circumstance: 周囲に(circum)立っ(sto)ていること(-ance) -> 周囲の事情、環境、状況
- distance: 離れて(dis-)立っ(sto)ていること(-antia) -> 距離、離れた場所
- obstacle: 前に(ob-)立つ(sto)道具(-culum)、邪魔なもの -> 障害物、妨害物、邪魔
confirm: 完全に(con-)堅固にする(firmo)こと -> 確かめる、承認する
- affirm: 支持する、断言する
- firm: 堅い(firmus)こと -> 堅い、頑丈な、断固とした
- firm: 取引を堅固(firmus)にするために文書に署名した屋号 -> 商会、会社、事務所
execute: 外まで(ex-)付いていく(sequor)、最後までやり通す、遂行する -> を実行する、を施行する、を処刑する
- exective: 外まで(ex-)付いていっ(sequor)ている(-ivus)、最期までやり通している、遂行している -> 役員、実行する、行政の
- suit: sequor(後を追う) -> ぴったりと(sequor)あった服、罪の追求(sequor) -> スーツ、訴訟、適合するもの、似合う、服を着せる
- second: 最初の数の後に続い(sequor)ている(-undus)数 -> 第二の
- second: 第一の時間の小さな単位 [minute] に続く第二の(secunda)小さな(minutus)単位(pars) -> 秒、瞬間、一刻
- persue: 前にあるものを(pro-)追い掛ける(sequor)こと -> 追跡する
- persuit: 追撃
- sequence: 続い(sequor)ている(-ens)こと(-ia) -> 連続、数列、順序
- sequel: 続編
- consequent: 一緒に(com-)後から続い(sequor)ている(-ens)こと -> 結果として生じる、当然の
- subsequent: 下に(sub-)続い(sequor)ている(-ens)こと -> 次の、後続の
まとめ
- テストの基本は、
expect().to matcher()
- これを
example
単位で書いていく it〜end
とかdescribe〜end
とかでグループ化
- これを
- エラーメッセージを含むときは
include
、同じ時はeq
- 手が止まったら、コンソールとか
binding.pry
で状況確認。
GitHubおさらい + よくあるエラー
英語がわかるとマジで面白い。
(何の勉強?笑)
英単語(復習含む)
migrate:ラテン語 migro(移住する) -> 移住する。渡りをする。
- immigrate: in-(中に)+migro(移住する) -> 他国から移住する。
- immigrate: in-(中に)+migro(移住する) -> 他国から移住する。
description: de-(~から下に)+scribo(書く) -> 記述。説明。描写。
- describe:~から(de-)書く(scribo)、描写する -> 述べる、言い表す、描写する
- script: scribo(書く) -> 台本。脚本。手書き。
- prescribe: prae-(~の前に)+scribo(書く) -> 規定する。指示する。処方する
- ascribe: ad-(~へ、~に)+scribo(書く) -> ~のせいにする。~に帰する。~のものと見なす
- subscribe: sub-(下に)+scribo(書く) -> 「署名」がコア -> 署名する。承認する。予約する
- transcribe: 越えて(trans-)書く(scribo) -> 書き写す、転写する、翻訳する
squash:askut「青い、生の、未加工の」 -> asquash「食べられる」 -> 押しつぶす、ぐちゃぐちゃにする
- スポーツのスカッシュは、ボールのスピードが出過ぎるからって、ボールをぐちゃぐちゃにしたのが始まりとかなんとか。(ほんとかよ)
- スポーツのスカッシュは、ボールのスピードが出過ぎるからって、ボールをぐちゃぐちゃにしたのが始まりとかなんとか。(ほんとかよ)
via:~の道(via)を通って -> ~を通って、~を経由して
revert: 後ろへ(re-)向きを変える(verto)こと -> 立ち戻る、戻る、復帰する
- conbert: 完全に(con-)向きを変える(verto) -> 変形する、変質する、転換する
- conbert: 完全に(con-)向きを変える(verto) -> 変形する、変質する、転換する
conflict: 衝突、競争
discard: dis-(離れて)+card(トランプの札) -> 捨て札。捨てる。切り捨てる。
- chart: charte(図) -> 図、表
- card: charta(図) -> カード。トランプの札
propose: 前へ(pro-)置く(pono) -> を提案する、に結婚を申し込む、を企てる
- suppose: 下に(sub-)置く(pono)、仮定として置く -> 仮定する、~だと思う、前提とする
- compose: ばらばらのものを組み合わせて一緒に(com-)置く(poser)こと -> 構成する、作曲する、落ち着かせる
- deposit: 手元から離れた(de-)場所へ置く(pono)こと -> 預ける、貯金する
- dispose: それぞれ別々に(dis-)正しく置く(pono)こと -> 配置する、並べる
- oppose: ob-(~に対して)+pauso(停止する) -> と敵対する、に反対する、を対比させる
- purpose: 前へ(pro-)置く(pono) -> 目的、決心
collaborate: 一緒に(com-)働く(laboro) -> 協働する、協力する、共同して働く
- laboratory: 作業する(laboro)人(-tor)が使う場所(-arium) -> 実験室、研究室、製造所
- labor: 肉体的な仕事(labor) -> 肉体的な仕事、労働者
params深掘り
paramsの使い所がわかりません
エラーの原因を探るときに、時々使われているけど、自分で使おうと思ってもさっぱり。
とりま、いつ何が入るのか追いかけてみる。
- createアクション内に
binding.pry
10: def create 11: @post = Post.new(post_params) 12: 13: if @post.valid? #valid? 14: @post.save 15: 16: redirect_to root_path 17: => 18: binding.pry 19: else 20: render 'new' 21: end 22: end
(コンソールでparams
と入力)
[1] pry(#<PostsController>)> params => <ActionController::Parameters { "authenticity_token"=>"Ka2ubHwLc・・・Bp8g", "post"=>#<ActionController::Parameters {"title"=>"d", "content"=>"d"} permitted: false>, "commit"=>"投稿する", "controller"=>"posts", "action"=>"create" } permitted: false>
- 続いて
index.html.erb
内にbinding.pry
=> 1: <% binding.pry %> 2: <% @posts.each do |post| %> 3: <%= render partial: "post", locals: { post: post } %> 4: <% end %>
(同じくコンソールでparams
と入力)
[1] pry(#<#<Class:0x000000010ceb71e0>>)> params => <ActionController::Parameters { "controller"=>"posts", "action"=>"index" } permitted: false>
解説
ActionController::Parameters
- これは、paramsというメソッド(変数?)を定義しているファイルとのこと。
- これは、paramsというメソッド(変数?)を定義しているファイルとのこと。
例えば、posts_controller.rb
の冒頭は、
class PostsController < ApplicationController
続いて、applicationcontroller.rb
の冒頭が、
class ApplicationController < ActionController::Base
=> どうやら、全てのコントローラーはActionControllerを継承していおり、そのActionController内にparamsの定義的なものが入っている、という構図のよう。
"controller"=>"posts", "action"=>"create"
- これらは「どのアクションを実行するか」という情報として保持されている。
(どちらのアクションでも共通:それ故にいろいろなアクションが実行される)
- これらは「どのアクションを実行するか」という情報として保持されている。
"authenticity_token"=>"Ka2ubHwLc・・・Bp8g"
authenticity
=信憑性*1- 信憑性を担保するために、登録するデータと一緒にランダムな文字列を紐付け、一異性を確保しているとのこと。
"post"=>#<ActionController::Parameters {"title"=>"d", "content"=>"d"} permitted: false>,
post
モデルに対する操作情報を保持- これによってテーブルにデータが保存される。
まとめ
paramsの挙動をまとめると以下の3つ。
- 動作 + 属性値 をハッシュ構造として持つ
- URLとして動き始めたときに値が更新
- アクションを実行し終わるまで値を保持
結果、値を変えながらMVCの中をぐるぐるぐるぐる。
実は、フレームワークという枠組みの中で根幹的な役割を果たしている(っぽい)。
*1:authentic: autos(自分自身)+hentes(行為者) -> 権威ある独裁者 => 本物の、信頼のおける、確かな
automatic: 自分(autos)で考えて(men-)動く物の(-ic) -> 自動の、無意識の
出典:語源英和辞典 – 英単語のコアの語源が理解できる辞書
GitとGitHub
Key-Word
リポジトリー:貯蔵庫
- repository:語源はre(後ろ)とponere(置く) -> 貯蔵庫
- repository:語源はre(後ろ)とponere(置く) -> 貯蔵庫
Gitの設定:不要な変更履歴が残らないように
〜/.gitignore_global
を作成して.DS_store
記載。- ホームディレクトリーで
git config --global core.excludesfile ~/.gitignore_global
ローカルレポジトリのcommit履歴は、GitHub desktopで。
== commit log - commit + push -> リモートレポジトリに反映 == GitHunで確認
ブランチを切る:commitの連なり、を枝分けれさせる。
- ブランチは実装機能ごと、または変更修正作業ごとに作成
- ブランチは実装機能ごと、または変更修正作業ごとに作成
- git clone(ギット クローン)コマンド
#リモートリポジトリのURLに.gitを加えた文字列 % git clone (ダウンロードしたいリモートリポジトリのURL) #└何回か出てきたことない?
pull
は、ローカルとリモートが紐づいたときに使う。
clone
は、リモートしかないときに使う。(clone
したら紐付く)
英単語
- split:引き裂く(spel-)こと -> 引き裂く、割る
- spill: spel-(引き裂く)が語源 -> こぼす
- spill: spel-(引き裂く)が語源 -> こぼす
unify:uni(一つ) -> 一つに統合する。
fetch:ped-(歩く)が語源。「歩いて取ってくること」がコア -> 取ってくる。連れてくる。取ってくること。
- foot(足)と同じ語源。
- fetching:魅力的な
- fetisism:フェティッシュ(物神、呪物) -> 断片を偏愛する態度の (音は近いけど語源は別っぽい。)
repository(再掲):語源はre(後ろ)とponere(置く) -> 貯蔵庫
commit:一緒に(com-)送る(mitto)、協力する、任せる -> に全力を捧げる、結果を約束する、積極的に関わる
- commition:一緒に(com-)送る(mitto)こと(-tio) -> 委託、任務
- commitment:委ねる(commit)こと(-ment) -> 献身、責任、約束
- admit:~に(ad-)送る(mitto)、中に入れる -> 認める、許す、許容する。
- permit:~を通り抜けて(per-)送る(mitto)、見逃す -> を許可する、を認める
- submit:下に(sub-)置く(mitto) -> を提出する、を服従させる
- transmit:越えて(trans-)送る(mitto)、別の場所へ送る -> を送信する、を伝達する、を伝染させる
branch:古期フランス語 branche(枝) -> 枝。支店。分家
- branchbanking:支店銀行制
- branchbanking:支店銀行制
enterprise:引き受けること(entreprise)、引き受けた仕事、事業 -> 企業、事業、活動
- comprise:全体をまとめて一緒に(com-)つかむ(prehendo)こと -> 包含する
- surprise:上から(sur-)急につかんで(prehendo)奪取すること -> 驚き、奇襲
conflict: con-(一緒に)+fligo(打つ)が語源。「打ち合うこと」がこの単語のコア -> 衝突。紛争。対立する
- inflict:ラテン語 in-(上に)+fligo([strike] 打つ;襲う)が語源。「打撃を加えて苦しめること」がこの単語のコア -> 課す。苦痛を押し付ける
- inflict:ラテン語 in-(上に)+fligo([strike] 打つ;襲う)が語源。「打撃を加えて苦しめること」がこの単語のコア -> 課す。苦痛を押し付ける
confirm:完全に(con-)堅固にする(firmo)こと -> 確かめる、承認する
- affirm:断言する
- affirm:断言する
restore:再び(re-)元の状態に戻す(stauro)こと -> 元の場所に返す、元の状態に戻す、回復させる
- store:元の状態に戻す(instauro)、元の状態に戻すために補充する -> 蓄える
- storage:英語 store(蓄える)+-age(行為) -> 貯蔵、貯蔵場所、記憶装置
origin:origo(始まり) -> 発端。起源。先祖。
- abort:誕生(orior)から離れる(ab-)、流産する -> 胎児を流産する、中止する
- orient: orient(東)+-er(動詞語尾) -> orior(立ち上がる)+-ens(現在分詞語尾) -> 東向きにする。正しい方向に置く。適応させる。
サービス設計
ニュー単語
デプロイ:公開
- depoly:折ら(ploiier)ない(des-) -> 配備する、配置する、展開する
- depoly:折ら(ploiier)ない(des-) -> 配備する、配置する、展開する
ペルソナ:サービスを使用するユーザー(ターゲットとは似て非なる言葉。)
- persona:語源不詳 -> 仮面、役柄、人物
- 派生語 person:人物
ユーザーストーリー:ペルソナの課題に対して、機能をあてがうこと。(解決までのストーリー)
要件定義:機能を言語化。チームで共通認識を持つ。
基本設計:大枠を固める。画面や画面遷移の流れ
詳細設計:具体のコードを決める。必要な処理をコード化。
DB設計:エンティティの抽出。エンティティ≒テーブル。登録される瞬間を意識。
外部キー:テーブル同士が、「1対多」の関係にあるとき、多の方に設定する。
usersとtweetsの関係
users | tweets |
---|---|
1 | 多 |
↓
tweetsテーブル(子)にuserテーブル(親)の情報を書く
id | tweet | user_id |
---|---|---|
35 | hoge | 1 |
モデリング:エンティティの関係性とかを図示。
正規化:DBの効率的でシンプルな形に
- 非正規形:全部の情報を一つのテーブルにごちゃ混ぜに登録してる状態
- 第一正規形:重複削除
- 第三正規形:エンティティを分離してアソシエーションで整理。(二と三はほぼ同義)
制約:DBに直接設定するデータの制限。概念としてはvalidate*1と近い。
└後からの変更は大変なので、最初によく考える。
- NOT NULL制約:nullはダメ制約
t.string :name, null: false
一意性制約:一意じゃないとダメ制約。
主キー制約:主キーに対して、NOT NULL かつ 一意性制約
外部キー:存在しないキーに連携させてはダメ。連携されてるデータを消してはダメ。
= 連携された状態で存在することを保証。
t.references :user(カラム名), foreign_key: true
チェック制約:文字数制限とかをチェック
ER(Entity Relationship)図:文字通りの図
気づき
- 長いページは先に一通り流し見して、ワード(or 項目)を抜き出してから、詳細を読み進める。
英単語
entity:存在している(ens)こと(-ity) -> 存在物、実在、本質 => サービスで扱われる情報
- essential:存在(esse)している(-ens)こと(-ia)の(-alis) -> 絶対必要な
- essential:存在(esse)している(-ens)こと(-ia)の(-alis) -> 絶対必要な
depoly:折ら(ploiier)ない(des-) -> 配備する、配置する、展開する
- (関連語)employ:中に(in-)折り込む(plico)こと -> 雇う、採用する、用いる
*1:validate:検証する
requireとpermit
エラー問題めちゃくちゃ時間かかる。(2日かけて問題1 笑)
怪しい箇所の候補があまり浮かんでこない。
けど、数学の問題解いてるみたいで楽しい。
binding-pry
で裏側の動き見る感じ、もっと使いこなしたい。
もっとちょうだい。
form_with => params の中身
<ActionController::Parameters { "authenticity_token"=>"xxx", "post"=>{"title"=>"shige", "content"=>"tage"}, "commit"=>"投稿する", "controller"=>"posts", "action"=>"create" } permitted: false>
require(モデル名)
モデルに対応したキーがあるか確認。あればバリューを返す。
params.reqire(:post) => <ActionController::Parameters { "title"=>"shige", "content"=>"tage" } permitted: false>
require 補足
params[:post]でも同じ結果が得られる
params[:post] => <ActionController::Parameters { "title"=>"shige", "content"=>"tage" } permitted: false>
Railsの基本機能として、このように複数のキーとバリューのセットを一括処理することができる( == マスアサインメント機能)。ぱっと見便利。
が、例えばChormeの検証モードを使うとフォームの加工とか、送付されるparamsデータの加工は容易にできてしまう(らしい)。
permit(キー)
そこで登場するのがpermitメソッド。あらかじめ許可するキーを指定しておき、悪意ある書き込みを防止する。
params.require(:post).permit(:title, :content) => <ActionController::Parameters {"title"=>"shige", "content"=>"tage"} permitted: true>
└最後がpermitted: true
(許可)になってて腹落ち。
英単語
- syntax:syn-「一緒に」とtassein「整える」(tactics) -> 整理する => 文法的な構造、組み立て
用法:syntax error! == 構文のエラーだよ
デバッグ
ことば
debug:de(否定)bug(虫) -> バグを取り除くこと
bind:bhend-(縛る)が語源 -> 縛る、くくる、拘束する
手順
- pry-rails導入
gem 'pry-rails' => bundle install
binding.pry
を一時停止したいところに記述。(bind:拘束)- すると、そこで動きが停止しコンソールが起動する
└パラメーターの確認などができる。
- すると、そこで動きが停止しコンソールが起動する
def create binding.pry Tweet.create(tweet_params) end => tweetを投稿しても、createアクション(tweetの保存)は発生しない。
[1] pry(#<TweetsController>)> params => paramsを取得 => 気が済んだらexit
大事なこと
- どう書くかより、どこに何が書かれているかを今一度把握する必要がある。でないとエラー(の場所)を探せない。
- 大事なのは、仮説を立ててそれを1つ1つ検証していくこと。
pry-railsはあくまでそのための手段(ツール)。