RubyもRailsもSQLも知らんC++erですがいきなり戦いを挑んでみた

## はじめに

これまでC++、JavaScirpt、C#、Rustなどなどいろいろな言語を触ってきましたが、Rubyはほとんど触る機会がありませんでした。  
またデータベースも`SELECT`文というのがあるくらいの知識しか持っていませんでした。

ところでいろいろありお仕事で以下の新しい要素~~しかない~~に満ち溢れている領域への挑戦をすることになりました。

- Ruby
- Rails
    - Active Record
    - ActionView
    - etc
- Rspec
    - Factory Girl
- MySQL

無事にRailsチョットワカルになれたと思うのでそこで得た知見をまとめてみようかと思います。

## 環境構築

環境構築のはまりポイントもあったのですが職場の手順書が改善されてしまったので(いいことだけど)、書くモチベがないので割愛します。

## haml入門

```haml
- content_for :main_pane do
  = render 'new', :setting => @foo_setting
= render "common", :settings => @foo_settings
```

erbではなくhamlを使っている職場です。コードを見ていくと割と初めにこのようなファイルに遭遇します。Ruby/Rail初学者にとって、初見ではただの暗号にしか見えないでしょう。


### 部分テンプレート(=パーシャル)

まず`render`に注目します。これは別のファイルを解釈して描画させる指令です。ここで大事になるのがdirectory構成です。

```
├─foo_settings
│      index.html.haml
│      index.js.haml
│      new.html.haml
│      new.js.haml
│      _common.haml
│      _form.haml
│      _new.haml
```

例えば`render 'new'`のように書かれていたら`_new.haml`を描画しようとしているわけです。

この機能のことを部分テンプレート(=パーシャル)と呼びます。

`render`の後に`,`で区切られて渡されているのは引数と思えばいいです。例えば`render 'new', :setting => @foo_setting`に注目してみます。これで呼び出される`_new.haml`には

```haml
.arikitari-icon= theme_image_tag(setting.icon_path, :size => "48x48")
```

のような記載があります。`setting`という変数が使われていますね。

- [【Rails】 renderメソッドの使い方を徹底解説！ | Pikawaka - ピカ1わかりやすいプログラミング用語サイト](https://pikawaka.com/rails/render)
- [【超基本】railsで部分テンプレートを使ってみる（haml） - Qiita](https://qiita.com/rie1224/items/c6a9a647f669061fcbf4)

執筆段階になって思い出しましたが、そういえば昔ほんの少しだけ触れたPugにもそんな機能あった気がしますね  
[Includes – Pug](https://pugjs.org/language/includes.html)

### content_for

では次に`content_for :main_pane`に着目します。

これは`yield :main_pane`(ブロックなしで呼び出す`content_for`も同じ意味らしい)とされている箇所に以下の内容を描画させるよという意味合いを持ちます。なにかテンプレートがあってそこに中身を差し込んでいく感じです。

- [【Rails】content_forを理解するyieldを学ぶ - Qiita](https://qiita.com/onikan/items/2c2797833a02c0248ca3)
- [【Rails 】content_forとyieldの使い方 - Qiita](https://qiita.com/tomokichi_ruby/items/fdf4369ad4aaf45c7303)

執筆段階になって思い出しましたが、そういえば昔ほんの少しだけ触れたPugにもそんな機能あった気がしますね  
[Template Inheritance – Pug](https://pugjs.org/language/inheritance.html)

### `-`とか`=`とか

- `-`: Rubyのコードを書くけどそれらの結果をrenderしないときに
- `=`: Rubyとかのコードを書いて結果をrenderするとき

たぶんこれを見るのが一番速いと思います

- [決定版!!Haml小技まとめ！！ - Qiita](https://qiita.com/yukimura1227/items/a1cbf65ac9abd4d138e1)
- [Haml：変数を扱う | ハックノート](https://hacknote.jp/archives/4542/)

### `t`ってどんな関数？

`/app/views/functions/foo_settings/_new.haml`

```haml
.arikitari-summary.ui-helper-clearfix
  .arikitari-icon= theme_image_tag(setting.icon_path, :size => "48x48")
  %ul.arikitari-description
    %li= t("common.new")

.arikitari-tabs
  %ul
    %li= link_to t("functions.setting"), "#setting_tab"
  #setting_tab
    = render "form", :setting => setting
```

hamlを見ていると`t`というメソッド呼び出しが見つかると思います。でも`t`って何でしょう？ggrbilityが低そうですね。

~~[Rails 国際化 (i18n) API - Railsガイド](https://railsguides.jp/i18n.html#%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%A9%E3%82%A4%E3%82%BA%E3%81%95%E3%82%8C%E3%81%9F%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E6%8A%BD%E8%B1%A1%E5%8C%96%E3%81%99%E3%82%8B)~~

~~国際化(多言語)対応のための関数です。`i18n.t`でも呼び出せます。~~

嘘です違いました。`TranslationHelper#translate`のことで、`I18n.translate`(`I18n.t`)をviewからよぶ上でのいろいろな考慮がされたものになるようです。

https://qiita.com/masa_ito/items/c40d2fa76c8a0e364642

余談ですがi18nはinternationalizationの略で先頭の i と語尾の n の間が18文字である所から来ています。

## デバッグ環境を作ろう

いろいろ説明されても正直よくわからない、実働を見ながら理解したいことってありますよね。またそもそもバグって動かん時にデバッグできないと困ります。デバッグできるようになりましょう。

### VSCode

Ruby plugin入れた後に`.vscode/launch.json`をいい感じに書くことで使えるようになります。

どうやって設定作ったかは記憶の遥か彼方に消えてしまったのですが、VSCodeでプロジェクトのdirectoryを開いている状態で左のデバッグタブを押して、`create a launch.json`を選び、Rubyを選択すれば大体以下のような感じのものが吐かれた気がします。まあ違ったら手書きすればいいわけで。

```json5
{
    // Use IntelliSense to learn about possible attributes.
    // Hover to view descriptions of existing attributes.
    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "RSpec - active spec file only",
            "type": "Ruby",
            "request": "launch",
            "program": "${workspaceRoot}/bin/bundle",
            "args": [
                "exec",
                "rspec",
                "-I",
                "${workspaceRoot}",
                "${file}"
            ],
            "useBundler": true,
        },
        {
            "name": "Rails server",
            "type": "Ruby",
            "request": "launch",
            "program": "${workspaceRoot}/bin/rails",
            "args": [
                "server",
                "-p",
                "3000",
                "-b",
                "0.0.0.0"
            ],
            "useBundler": true,
        }
    ]
}
```

あとはF5でデバッガーが立ち上がってブレークポイント打てばそこで止めて変数見たりできます。

ただしデバッガーでRailsとかRspec動かすのはめちゃくちゃ遅いです。使ったことないですが[`logger.debug`](https://qiita.com/Kashiwara/items/f8a4030da6b17e96fabf)で原始的にprint debugとかしたほうがいい場面もあるかもしれないですね。

- [VScodeでRailsをデバッグする - Qiita](https://qiita.com/arashida/items/f5236b145aec5055bfb3)
- [VScode上でRailsのステップデバックする方法 - Qiita](https://qiita.com/satreu16/items/0a9e7396308a3b83b88b)
- [RSpecのデバッグ環境をVS Codeで構築する | memoTech](https://tech.blog.home.group.jp/archives/150)
- [Visual Studio Codeでruby-debug-ideを使ってデバッグ - アトトックラボ｜株式会社アトトック](https://atotok.co.jp/labo/1ae604a17b60ad17fac0b7198c914ff0)

### binding.pry

コンソールでデバッグしていくやつです。VSCodeのデバッガーより軽量ですし、Active Recordみたいに何のメソッド生えてるのかわからんときに、VSCodeのデバッガーだと追いずらい一方でbinding.pryならメソッド一覧が取って来れるので、どうやって子テーブルアクセスすりゃいいの？ってときにも役立つかもしれないですね。

デバッガーでブレークポイントを打つのと同じ感覚でソースコード中に`binding.pry`と書き、普通にプログラムを実行すると、当該箇所を通過したときにデバッガーになります。

- [binding.pryの基本的な使い方 - Qiita](https://qiita.com/daisuke19840125/items/c8e422f7a17fb95de283)
- [デバックツール(pry-rails)について　binding.pryの使い方 - Qiita](https://qiita.com/STHEXA/items/1de2411cb3987066c9b9)
- [今更聞けないpryの使い方と便利プラグイン集 - Qiita](https://qiita.com/k0kubun/items/b118e9ccaef8707c4d9f)
- [wtf!!!!!!!!!!!!!!!!!!!!!!?????????????????? - Qiita](https://qiita.com/okuramasafumi/items/1e0415a10dc5d4a3ea90)
- [binding.pry から脱出するコマンド - Qiita](https://qiita.com/hachiya/items/1023dffb870ef20dc4cd)
- [ruby on rails - How do I dump Pry output to a file or Vim? - Stack Overflow](https://stackoverflow.com/questions/20979356/how-do-i-dump-pry-output-to-a-file-or-vim)

## Ruby入門

基本的にるりまを見ることになります。

- [プログラミング言語 Ruby リファレンスマニュアル](https://docs.ruby-lang.org/ja/)
- [最速Rubyリファレンスマニュアル検索！ | るりまサーチ](https://docs.ruby-lang.org/ja/search/)

とくにRubyはほかの言語に比べてよくわからない記号が出てきがちなので  
[Rubyで使われる記号の意味（正規表現の複雑な記号は除く） (Ruby 3.0.0 リファレンスマニュアル)](https://docs.ruby-lang.org/ja/latest/doc/symref.html)  
にしばしばお世話になることでしょう。

### Symbol

> [class Symbol (Ruby 3.0.0 リファレンスマニュアル)](https://docs.ruby-lang.org/ja/latest/class/Symbol.html)
> 
> シンボルは任意の文字列と一対一に対応するオブジェクト
>
> Rubyの内部実装では、メソッド名や変数名、定数名、クラス名などの**名前**を整数で管理しています。

つまるところ大抵の識別名はSymbolとして管理されます。

```ruby
:foo
```

のようにして明示してシンボルを作れますし、また使用できます。

C/C++などでは、コンパイラの最適化によって登場する文字列は定数テーブルに配置されるのが大抵の処理系で行われますが、その代わりとしてRubyではSymbolがあるのでしょう。

Symbolの配列をつくることも時としてあるかと思いますが、`%i`記法が便利です。

```ruby
%i(foo bar)
```

- [class Symbol (Ruby 3.0.0 リファレンスマニュアル)](https://docs.ruby-lang.org/ja/latest/class/Symbol.html)
- [Rubyの文字列とシンボルの違いをキッチリ説明できる人になりたい - Qiita](https://qiita.com/Kta-M/items/53a13ef60e14fcb41193)
- [Rubyで%記法（パーセント記法）を使う - Qiita](https://qiita.com/mogulla3/items/46bb876391be07921743#6-i)
- [Class: RuboCop::Cop::Lint::PercentSymbolArray — Documentation for rubocop (1.20.0)](https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Lint/PercentSymbolArray)
- [Class: RuboCop::Cop::Style::SymbolArray — Documentation for bbatsov/RuboCop (master)](https://www.rubydoc.info/github/bbatsov/RuboCop/RuboCop/Cop/Style/SymbolArray)

### hash(連想配列)

大抵の言語で存在する連想配列/dictionary/hashのようなkeyとvalueがあるデータ構造ですがもちろんRubyにもあります。

なおhashというとC++erは`std::hash`を思い浮かべるでしょうがそっちではないです。

```ruby
{} # 最小の(?) Hash
{ foo: 3 } # keyが:fooで値が3
{ :foo => 3 } # 上と同じ意味だけど古い書き方
```

```ruby
h = { foo: 3}
p h[:foo] # => 3
h[:foo] = 4
p h[:foo] # => 4
```

- [class Hash (Ruby 3.0.0 リファレンスマニュアル)](https://docs.ruby-lang.org/ja/latest/class/Hash.html)
- [Rubyのhash宣言方法いろいろ - Qiita](https://qiita.com/yukimura1227/items/8c972efb27667dfac5cd)

### `operator ===` vs `operator ==`

JavaScriptだと`operator ==`は比較が厳密じゃないから`operator ===`使おうというのが一般的な見解になっていますがRubyはどうなのでしょうか？

結論から言うと`operator ===`は常用するものではなさそうです。Rubyの`case`文の判定に内部的に使われているようですが、[`is_a?`](https://docs.ruby-lang.org/ja/2.4.0/method/Object/i/is_a=3f.html)/[`include?`](https://docs.ruby-lang.org/ja/2.4.0/method/Enumerable/i/include=3f.html)/[`match?`](https://docs.ruby-lang.org/ja/2.4.0/method/String/i/match=3f.html)を使おうとRubocop先生も怒ってきます。

```ruby
# bad
Array === something
(1..100) === 7
/something/ === some_string

# good
something.is_a?(Array)
(1..100).include?(7)
/something/.match?(some_string)
```

- [Class: RuboCop::Cop::Style::CaseEquality — Documentation for rubocop (1.20.0)](https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/CaseEquality)
- [Object#=== (Ruby 3.0.0 リファレンスマニュアル)](https://docs.ruby-lang.org/ja/latest/method/Object/i/=3d=3d=3d.html)

### nullアクセスを避けるには

最近の言語ではオプショナルチェインとかそんな名前で、プロパティ/メソッドに多段階にアクセスするときに、nullチェックをいちいち書かないでもやってくれるような構文がありますが、Rubyはどうでしょうか？

#### ボッチ演算子

`&.`のようにアクセスすることでnull参照を避けられます。その見た目からボッチ演算子と呼ばれることが多いようです。

```ruby
@nickname = current_user&.nickname
```

なおかつてはRails(Active Support)の`try`メソッドが用いられたようですが、現在では考古学の対象のようです。

- [Ruby ぼっち演算子について - Qiita](https://qiita.com/yoshi_4/items/e987b698c1978d248cfc)
- [Active Support コア拡張機能 - Railsガイド#try](https://railsguides.jp/active_support_core_extensions.html#try)
- [【Ruby on Rails】tryとtry!と&.（ぼっち演算子）の違い - Qiita#tryは使わない方が良さそう](https://qiita.com/massaaaaan/items/ce5856559e55e85b69d8#try%E3%81%AF%E4%BD%BF%E3%82%8F%E3%81%AA%E3%81%84%E6%96%B9%E3%81%8C%E8%89%AF%E3%81%95%E3%81%9D%E3%81%86)

#### Hash#dig

Q:

```ruby
foo.key?(:aaa) ? foo[:aaa][:bbb] : nil
```

を[もうちょっとすっきり書く方法、Rubyでご存じの方いますか？](https://qiitadon.com/@yumetodo/106616314612967620)

A: [Hash#digを使うとかですかね？](https://gamelinks007.net/@S_H_/106616329191165830)

```ruby
foo.dig(:aaa, :bbb)
```

- [Hash#dig (Ruby 2.4.0 リファレンスマニュアル)](https://docs.ruby-lang.org/ja/2.4.0/method/Hash/i/dig.html)

### NullObject Pattern

ボッチ演算子も`try`も`Hash#dig`もnil対する対処をしているわけですが、その責務は誰が持つべきか？オブジェクトを生成するところの責務では？というのがNullObject Patternです。

```ruby
class Element
    def bar
        # return some string
    end
end
class NoElement
    def bar
        "no element"
    end
end
def foo
    xxx.element || NoElement.new
end
def hoge
    foo.bar # always ok, nil check is not required
end
```

[`Hash#new`](https://docs.ruby-lang.org/ja/latest/method/Hash/s/new.html)なんかもこういう用途に使えたりします。

C++では以下のように使うべきではない理由しかないので見向きもされない印象です。

- そもそもC++ではオブジェクトをポインタで扱うとかmove semanticsでも使わない限り全てはコピーされるという契約が成り立つがこれがNullObject Patternと相性が悪い(実現のために書くコードが多い)
- 仮想関数を使うことになるので最適化を阻害する
- しかも実質shared_ptrでの取り回しをユーザーに要求するので不自由

そもそもNullObject Patternを言い出したJava界隈を観測してみましたが否定的な意見が見つかりますし理由も個人的には納得が行きます。

> [失敗を表現する手法としてNullObjectパターンが不適切でEitherが適切だと思う理由 - Qiita](https://qiita.com/suzuki-hoge/items/b8161d29094224415f1e)
>
> NOPはinterfaceを用いて成功と失敗の同一視を行います。
対してEitherはinterfaceを用いず成功と失敗は別視します。
>
>そしておそらく2つの具象クラスは少し振る舞いやステータスが違う程度なのでしょうから、例えばDB保存もどちらも出来そうです。
その点においてもこの例は「成功と失敗」ではなく「成功1と成功2」であると考えられます。
>
> - NOPを用いている箇所は、以下のどちらかに発想を遷移させるのが適切
>   - 具象クラスの関係が同一視であれば、適切な抽象化を行いストラテジパターンにする
>   - 具象クラスの関係が対の関係であれば、interfaceを無くしEitherを用いる

ただまあRubyなら出番もあるのかもしれないですね。

- [Rails tips: Null Objectパターンでリファクタリング（翻訳）｜TechRacho by BPS株式会社](https://techracho.bpsinc.jp/hachi8833/2018_03_22/53800)
- [Active RecordとNull Objectパターン](https://zenn.dev/ytnk531/articles/4719dd13bab3ff)
- [C++で迷走してみる - おっさんプログラマの戯れ言](https://unk-pizza.hatenadiary.org/entry/20140502/p1)

### lambdaとかブロックとかprocとか

2010年代の関数型プログラミングブームの成果もありC++にすら導入されたlambda(式)。Rubyはどうでしょうか？

#### block

下手にC++のlambda式とかJavaScirptの関数を知っていると理解を阻害されそうですが、めげずに見ていきます。

まずとあるメソッドがあります。

```ruby
def foo(n)
    puts "foo #{n}"
end
foo(2)
```

このメソッドに処理の塊を渡したい

```ruby
#{ puts "aaa" }# 単体でblockを書くことはできない
def foo(n, &aaa)
    puts "foo #{n}"
end
foo(2) { puts "aaa" }#メソッド呼び出しの文脈でならかける
```

例から明らかなように、blockはメソッド呼び出しの文脈でのみ許可されます。

#### proc

blockは単体で存在できません。なぜならばオブジェクトではないからです。これをオブジェクトに変換できれば単体で存在できるようになるはずです。

```ruby
def bar(&a)
    a 
end
def foo(&a)
    bar(&a)
end
b = foo { puts "a" }
b.call # => a
```

`foo`メソッドはblock引数`a`を受け取ります。この段階、つまり`&`の効用によって**blockはオブジェクトに変身する準備を終えています**。そしてそのまま`bar`メソッドに渡されています。この`bar`メソッド内で初めて参照されるわけですが、この段階になってようやくblockはobjectに変身を遂げます。もちろん`foo`メソッドに帰ってきたとき、依然として`&a`は`proc`オブジェクトではありません。

こうしてできたprocオブジェクトを返すので変数`b`はもちろんprocオブジェクトです。

procオブジェクトは`call`することで処理を実行できます。

もちろんいちいち上のように`foo`メソッドを定義するのは面倒極まるので`proc`というメソッドが用意されています

```ruby
b = proc { puts "a" }
b.call # => a
```

#### block再び

```ruby
def foo(n, &aaa)
    puts "foo #{n}"
    aaa.call
end
foo(2) { puts "aaa" }
```

メソッドはただ一つだけblockを引数として取れるのでした。では受け取ったblockを実行するにはどうするかというと引数で`&aaa`と書いた時点ですでにprocオブジェクトになる準備を終えているので、`call`すればprocオブジェクトになり、実行できるわけです。

ところでなぜかRubyにはblock引数を実行する方法があります。`yield`です。

```ruby
def foo(n, &aaa)
    puts "foo #{n}"
    yield if block_given?
end
foo(2) { puts "aaa" }
```

わざわざ`aaa`という引数名を付けてあげたのに使ってない・・・だと？したらばそれはいらないのでは？

```ruby
def foo(n)
    puts "foo #{n}"
    yield if block_given?
end
foo(2) { puts "aaa" }
```

かくして`yield`だけになりました。どうしてそうなった。

ただし、ブロックを受け取ることを意図したメソッドはちゃんと引数でもそう示したほうが良いような気がします。びっくりしてしまいますから。


もちろんblockは引数を取れます。

```ruby
def foo(&a)
    yield 3 if block_given?
end
foo {|n| puts "a #{n}" }
```

#### do...endもまたブロックである

```ruby
def foo
    yield
end
foo do
    p "a"
end
```

これまで`{}`の中に処理を書いてきましたが、`do...end`でも同じことができます。複数行になるときはこっちを使いがちな印象があります。

この2つでは結合強度が違うのだそうですが、そういうのに依存しないように書きたいですね。

- [メソッド呼び出し(super・ブロック付き・yield) (Ruby 3.0.0 リファレンスマニュアル)](https://docs.ruby-lang.org/ja/3.0.0/doc/spec=2fcall.html#block)
- [do...endと{...}の違い - おもしろwebサービス開発日記](https://blog.willnet.in/entry/20081015/1224043228)
- [Rubyのブロック構文の書き分け(do end，{}) - ぬいぐるみライフ？](https://mickey24.hatenablog.com/entry/20100914/1284475769)
- [プロと読み解くRuby 2.7 NEWS - クックパッド開発者ブログ](https://techlife.cookpad.com/entry/2019/12/25/121834)

#### lambda

基本的にprocと同じですが引数のチェックが行われることとreturnの挙動が違うようです。

```ruby
a = -> { 3 }
pp a
b = lambda { 3 }
pp b
c = proc {3}
pp c
```
    
[実行例](https://wandbox.org/permlink/vZJqOZx3QkY0Hok9)

```
#<Proc:0x0000564749e07cc0 prog.rb:1 (lambda)>
#<Proc:0x0000564749d94590 prog.rb:3 (lambda)>
#<Proc:0x0000564749d8d060 prog.rb:5>
```

`pp`しても区別されている感がありますね。

なおblockからlambdaは作れますが、procからlambdaを作ろうとする試みは大抵失敗に終わります。`lambda(&proc{})`とかがだめな典型例です。

- [Ruby block/proc/lambdaの使いどころ - Qiita](https://qiita.com/kidach1/items/15cfee9ec66804c3afd2)
- [【Ruby】ブロック・Proc・lambda を理解する - Qiita](https://qiita.com/k-penguin-sato/items/7f98335ef631ea5ce7ad)
- [まつもとゆきひろ×結城浩，Rubyを語る（3ページ目） | 日経クロステック（xTECH）](https://xtech.nikkei.com/it/article/COLUMN/20070621/275509/?P=3)
- [singleton method Proc.new (Ruby 1.9.3)](https://docs.ruby-lang.org/ja/1.9.3/method/Proc/s/new.html)
- [Feature #14045: Lazy Proc allocation for block parameters - Ruby master - Ruby Issue Tracking System](https://bugs.ruby-lang.org/issues/14045)
- [Class: RuboCop::Cop::Style::StabbyLambdaParentheses — Documentation for rubocop (1.20.0)](https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/StabbyLambdaParentheses)
- [プロと読み解く Ruby 3.0 NEWS - クックパッド開発者ブログ](https://techlife.cookpad.com/entry/2020/12/25/155741)

#### メソッドを関数の引数に渡すには

Cで言うところの関数ポインタみたいなものをどう実現するかということになりますが、Symbolを経由してやります。次の例を見ながら解説します。

```ruby
[1].map(&:next)
```

関連するメソッドは以下です。

- [Array#collect (Ruby 2.5.0 リファレンスマニュアル)](https://docs.ruby-lang.org/ja/2.5.0/method/Array/i/collect.html)
- [Integer#next (Ruby 2.5.0 リファレンスマニュアル)](https://docs.ruby-lang.org/ja/2.5.0/method/Integer/i/next.html)

`Array#map`は各要素について、与えられたprocオブジェクトを実行し、その結果の新たな配列を返します。

`:next`はそれ単体はSymbolなのにどうしてprocオブジェクトになるのか、その前の`&`で察するかもしれませんが次のように変換されるためです(`next_proc`は説明用の変数)。

```ruby
next_proc = :next.to_proc
[1].map{|i| next_proc.call(i)}
```

なお、どのクラスのメソッドなのかについては`call`の段階で第1引数がなにかによって解決されます。この辺はほかの言語と同じですね。

```ruby
a = :next.to_proc
pp a
p a.call(1)    # Integer#next
str = "xyz"
enum = str.each_byte
p a.call(enum) # Enumerator#next
```

`to_proc`はRuby3.0で仕様が変更されていて、lambdaオブジェクトを返すようになりました。結果、メソッドのアクセシビリティが無視されるようになるために次のコードが動くようになります

```ruby
def foo(n)
    p "a #{n}"
end
a = :foo.to_proc
pp a
a.call(nil, 2)
```

[実行結果](https://wandbox.org/permlink/pHXvfr0V69OdQAJh)

- [【Ruby】array.map(&:method)を理解する - Qiita](https://qiita.com/k-penguin-sato/items/420d7487b28b5d58cac4)
- [Proc#=== (Ruby 3.0.0 リファレンスマニュアル)](https://docs.ruby-lang.org/ja/3.0.0/method/Proc/i/=3d=3d=3d.html)
- [Symbol#to_proc (Ruby 3.0.0 リファレンスマニュアル)](https://docs.ruby-lang.org/ja/3.0.0/method/Symbol/i/to_proc.html)
- [Symbol#to_proc (Ruby 2.7.0 リファレンスマニュアル)](https://docs.ruby-lang.org/ja/2.7.0/method/Symbol/i/to_proc.html)
- [Feature #16260: Symbol#to_proc behaves like lambda, but doesn't aknowledge it - Ruby master - Ruby Issue Tracking System](https://bugs.ruby-lang.org/issues/16260)
- [yumetodo: "#ruby これ #wandbox が壊れているという認識であってるのかな、 >private m…" - Qiitadon](https://qiitadon.com/@yumetodo/106900100534598728)
- [Class: RuboCop::Cop::Style::SymbolProc — Documentation for rubocop (1.20.0)](https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/SymbolProc)

### クラスの特異メソッドと特異クラス

C++でいうstatic member functionsに近いものになるのでしょうが、Rubyにもクラスの特異メソッドがそれに該当します。

```ruby
class Foo
end
def Foo.bar
    "a"
end
Foo.bar # => a
Foo::bar # => a
```

classの中に書くこともできます

```ruby
class Foo
    def self.bar
        "a"
    end
end
```

特異クラスという機能を使って特異メソッドを定義することもできます。

```ruby
class Foo
end
class << Foo
    def bar
        "a"
    end
end
```

もちろん特異クラスを対象クラス内に書くこともできます

```ruby
class Foo
    class << self
        def bar
            "a"
        end
    end
end
```

- [Ruby 初級者のための class << self の話 (または特異クラスとメタクラス)](https://magazine.rubyist.net/articles/0046/0046-SingletonClassForBeginners.html)
- [【Ruby】特異メソッドについて - Qiita](https://qiita.com/ta-chibana/items/7965d246ab67e14c175a)
- [Ruby のクラスメソッド定義まとめ - Qiita](https://qiita.com/Linda_pp/items/b7135ae1f0def6058c6c)
- [yumetodo: "#ruby 自由すぎてわけわからんなｗ 特異メソッドこんなところにも生やせる https://wa…" - Qiitadon](https://qiitadon.com/@yumetodo/106905027786442888)

### Array#|

一見するとbit or演算子ですが、

```ruby
foo = nil
foo |= 0
p foo # => true
```

[実行結果](https://wandbox.org/permlink/kI9tvznQHb7rcB3m)

配列オブジェクトのメソッドとしても定義されていて、配列の和集合を返します。

一部のC++erは[`std::valarray::operator|=`](https://cpprefjp.github.io/reference/valarray/valarray/op_or_assign.html)を思い出すかもしれませんが、あれは各要素にbit or演算するものなので全く違います。

- [Array#| (Ruby 2.5.0 リファレンスマニュアル)](https://docs.ruby-lang.org/ja/2.5.0/method/Array/i/=7c.html)

### 他言語を呼ぶのにどうするか: Cのdllを呼ぶ

Win32APIを呼ぶようなときなど、CのAPIを叩くことはあろうかと思うのですが、どうすればいいでしょうか？

Win32API界隈で最近話題の[win32metadata](https://github.com/microsoft/win32metadata)を使うような方法はRubyには執筆現在ないようです。

そういうわけでFiddleを使うのが一般的のようです。[ffi](https://github.com/ffi/ffi)もあるのですが、Fiddleのほうがいいらしい。

> https://gamelinks007.net/@S_H_/106854866461791632
>
> ffiの場合はgemのinstall時にC拡張をビルドする必要があるので詰まる可能性が少なからずありそうかなぁと
>
>fiddleは確かRubyに組み込まれてるのでその辺が楽そうとか思いました
>
>まあ、どっちも使ったことがないのでどっちがいいかはよくわからないですね
>
>Rubyのコアに近いのでfiddleのほうがメンテナンス長くされそうという感じではありますが……

- [気まぐれDeveloperブログ: Rubyでdllやsoを扱うFiddleのまとめ](http://developabout0309.blogspot.com/2016/08/rubydllsofiddle.html)
- [module Fiddle::Win32Types (Ruby 3.0.0 リファレンスマニュアル)](https://docs.ruby-lang.org/ja/latest/class/Fiddle=3a=3aWin32Types.html)

## has_scope入門

controllerを触っていくようになると遭遇するであろう`has_scope`。後述するようにRailsに`scope`という機能があるがゆえに間違えがちですが全くの別物ですし、外部gemです。

[heartcombo/has_scope: Map incoming controller parameters to named scopes in your resources](https://github.com/heartcombo/has_scope)

わざわざ解説せずともReadme読めばわかる気がしますし、なんならライブラリは十分に小さいので[実装を読めばいい](https://github.com/heartcombo/has_scope/blob/master/lib/has_scope.rb)気もしますが簡単にまとめます。

検索フォームのようなものを実装するときを考えます。ふつうに考えてGET paramに検索キーを足してGET requestをクライアント側は投げてきますよね。

```
GET /some/endpoint?key1=aaa&key2=bbb
```

じゃあそれをどうパースして振り分けるのか。そこでhas_scopeの登場なわけです。

```ruby
class FooController < ApplicationController
    has_scope :key1 do |_, scope, value|
        # do something
    end
end
```

もしGET paramがつぎのような物だった場合どうするか

```
GET /some/endpoint?foo[x]=aaa&foo[y]=bbb
```

こんなかんじですね。`value`は要素2の配列になります。ここで`scope`は後述のActiveRecordのscope機能のほうを指します。

```ruby
has_scope :foo, using: %i(x, y), type: :hash do |_, scope, value|
    x, y = value
    scope.merge(
        # some active record relation
    )
end
```

あとはどこかで`apply_scopes`を呼び出す必要があります。

`has_scope`に長々書かず、modelのscopeを呼ぶための変換器くらいに割り切ったほうが健全な気がします。

- [javascript - My rails form is not working with has_scope - Stack Overflow](https://stackoverflow.com/questions/36264476/my-rails-form-is-not-working-with-has-scope)

## SQL入門

リレーショナルデータベースを操作すると言えばSQLですよね。

Railsのログを眺めていれば圧倒的SQLの物量に脳みそが強制的にSQLを理解するモードになるので心配はいりません。

[SQL Training 2021 - Speaker Deck](https://speakerdeck.com/yutamiyake/sql-training-2021?slide=2)

は一読しておくといいでしょう。

### DBの操作を強力に支援するツール: HeidiSQL

テーブル覗くのいちいちSQL組み立てるのは生産性がとてもよくないので、適当なツールが欲しいわけですが、HeidiSQLを紹介します。

Windows使いなら[chocolatey](https://chocolatey.org/install)はすでに導入しているはずなので、管理者権限Powershellで以下をたたくだけです。

```ps
choco install heidisql
```

VMの上のDockerでmysqlを動かしている場合、VMのhost名、username/password、portを調べればアクセスできるはずです。

テスト環境にVPN+SSH越しにDB覗く必要があるときは多少面倒で、任意のPuTTYgenに一度OpenSSH形式の鍵を読ませてppk形式で書き出し、それをHeidiSQLのSSHトンネルの項目で指定する必要があります。また本番環境のconfigを見てportを調べる必要もあります。

- [MySQLにHeidiSQLでアクセスする - セイコンサルティンググループ](https://saycon.co.jp/portal-for-newcomer/database/heidisql)
- [HeidiSQLのフィルタ機能の使い方 | ノウハウツリー](https://know-how-tree.com/archives/5315)
- [Windows と Linux でファイル形式 .pem と .ppk の間の相互変換を行う](https://aws.amazon.com/jp/premiumsupport/knowledge-center/convert-pem-file-into-ppk/)

## Rails

Railsではファイル名やModel名などなどに独特の命名規則の制約があります。だいたい単数形/複数形がよくわからなくなるやつです。公式ドキュメントを見て頑張りましよう。

- [Rails uninitialized constant エラーの解決へのシンプルなチェックリスト - Qiita](https://qiita.com/yoshixj/items/17de45928f52264fd6a0)
- [ruby on rails - "Uninitialized constant" error when including a module - Stack Overflow](https://stackoverflow.com/questions/11525350/uninitialized-constant-error-when-including-a-module)

### 基本構造: MVC

別にRailsに限ったことではなく、何らかのMVCとかMVVMとかなんらかの役割分担がされるのはこんにちの常識になっています。何のことかわからない読者は大急ぎで別途勉強しましょう。

RailsではMVC構造を採用しています。大体Controllerがでかくなって大変になるやつです。

私が触ったコードベースのdirectory構造はこれに大体対応していて大まかには以下の通りでした。

- app
    - controller: 飛んできたリクエストを捌く
    - model: databaseのtableと一対一対応し、その操作を担う
    - view: 画面周りを担う
        - helper: viewに書かざるを得ないロジックの共通化がここでなされる
    - assets: 画像/JS/CSSなどのリソース
- db
    - `schema.rb`: DBのテーブル構造とindex一覧、手動では基本弄らないでmigrationコマンドが書き換える
    - migrate: migration fileたちが集う。
- config
    - locales
        - 文言系のリソースがここに集う
    - routes.rb
        - ルーティング（どういうURLが叩かれたらどこのcontrollerにリクエストを転送すればいいか）を定義する
- lib: model向けのコードの共通化部分とか
    - assets: 画像/JS/CSSなどのリソース
- spec: rspec、つまり単体テスト

### ActiveRecord

RailsではActiveRecordを利用することで生のSQLを書くことはまああんまありません。実行ログに生のSQLが吐かれているのでそれが読めるようになる必要はあります。

例えば次のようなSQLは

```sql
SELECT
    *
from
    pre.foo
WHERE
    foo.name LIKE "%takahasi%"
ORDER BY
    foo.age ASC;
```

だいたい次のようになると思います。orderはcontrolllerの`has_scope`から渡されるんちゃう？とかそういう話は横において。

`model`

```ruby
class Foo < ActiveRecord::Base
   scope :search_name, lambda { |word|
       where('foo.name like ?', "%#{word}%")
       .order('foo.age ASC')
   } 
end
```

#### リンク集

SQLおよびそれをActive Recordで扱う時の入門で自分が調べたところをリンク集としてまとめておきます。

- create/build/new
    - [Rails モデルオブジェクト生成時のidがnilになる | | KeruuWeb](https://keruuweb.com/rails-%E3%83%A2%E3%83%87%E3%83%AB%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E7%94%9F%E6%88%90%E6%99%82%E3%81%AEid%E3%81%8Cnil%E3%81%AB%E3%81%AA%E3%82%8B/)
- INSERT
    - [INSERT文（SQLを基本から学ぶシリーズ）](https://products.sint.co.jp/topsic/blog/sql-insert)
    - [SQL INSERT文のサンプル | ITSakura](https://itsakura.com/sql-insert)
- LIKE
    - [Rails - LIKE句を使った文字のあいまい検索（特定の文字を含む語句を曖昧検索したい場合） - Qiita](https://qiita.com/seri1234/items/765423c2c46ca4114da0)
    - [Rails あいまい検索機能　LIKE句 - Qiita](https://qiita.com/nakanishi03/items/2a6dbd72f9793b7e0ce4)
    - [【Rails入門】where likeであいまい検索！複数条件やOR条件も解説 | 侍エンジニアブログ](https://www.sejuku.net/blog/71189)
    - [【SQL】LIKE句の基本的な使い方～複数検索する場合の方法まで解説 | ポテパンスタイル](https://style.potepan.com/articles/22072.html)
- ORDER BY
    - [railsでModelから引っこ抜いたデータの並び順を変えるOrderの使い方を極める - Qiita](https://qiita.com/makitokezuka/items/edca67ed23fa71b90997)
- GROUP BY
    - [ActiveRecordにおけるGROUP BYの使い方 - Qiita](https://qiita.com/yuyasat/items/e26bcf0eb2c89c63db9d)
- JOIN
    - [【INNER JOIN, LEFT JOIN , RIGHT JOIN】テーブル結合の挙動をまとめてみた【SQL】 - Qiita](https://qiita.com/ngron/items/db4947fb0551f21321c0)
    - [Rails における内部結合、外部結合まとめ - Qiita](https://qiita.com/yuyasat/items/c2ad37b5a24a58ee3d30)
    - [MySQL、2テーブルより値を結合しソートするテクニック（oreder by、union）｜レンタルサーバーナレッジ](https://knowledge.cpi.ad.jp/howto-cpi/163/)
    - [ActiveRecordのjoinsとpreloadとincludesとeager_loadの違い - Qiita](https://qiita.com/k0kubun/items/80c5a5494f53bb88dc58)
    - [漢(オトコ)のコンピュータ道: RDBにおけるキャッシュという考え方](http://nippondanji.blogspot.com/2015/06/rdb.html)
    - [実例で学ぶ、JOIN (NLJ) が遅くなる理屈と対処法 - Qiita](https://qiita.com/yuku_t/items/208be188eef17699c7a5)
    - [SQL Joinサンプル集　Joinで遅いSQLの原因を調べる方法 | ポテパンスタイル](https://style.potepan.com/articles/14926.html)
    - [S.H.: "@yumetodo@qiitadon.com それはHashの記法じゃないですかね Rubyだ…" - Creatodon](https://gamelinks007.net/@S_H_/106549826314127077)
- 正規化
    - [ActiveRecord serialize / store の甘い誘惑を断ち切ろう - Qiita](https://qiita.com/jnchito/items/68e91e9bf46f960a79e4)
    - [railsでmysqlのJSON型を扱う - Qiita](https://qiita.com/roark/items/55e87bc7576945a3fd1c)
- SUBSTRING_INDEX
    - [MySQL | SUBSTRING_INDEX関数 (指定した区切り文字よりも前または後の文字列を取得する)](https://www.dbonline.jp/mysql/function/index45.html)
- WHERE IDs
    - [How to select where ID in Array Rails ActiveRecord without exception - Stack Overflow](https://stackoverflow.com/questions/1441791/how-to-select-where-id-in-array-rails-activerecord-without-exception)
    - [ActiveRecord findメソッドにidを配列で渡した結果はRelationではない - Qiita](https://qiita.com/metheglin/items/f711f8ad3790d211cb79)
- pluck
    - [pluckメソッドとidsメソッドについて - Qiita](https://qiita.com/pandama09396862/items/aa7b60f5697fa63cbd95)
    - [【Rails】 便利なpluckメソッドの使い方をマスターしよう！ | Pikawaka - ピカ1わかりやすいプログラミング用語サイト](https://pikawaka.com/rails/pluck)

### scopeとmerge

ModelからControllerに対してレコードの操作を提供する入口として用いられます。驚き最小の法則にしたがい、ちゃんと`ActiveRecord::Relation`を返しましょう。びっくりしてバグるのでうっかりArrayとかを返さないように・・・。


```ruby
class Foo < ActiveRecord::Base
   scope :search_name, lambda { |word|
       where('foo.name like ?', "%#{word}%")
   } 
end
```

そうして作ったscopeやらその他`ActiveRecord::Relation`たちは最終的にmergeで結合するかと思います。

```ruby
has_scope :foo, using: %i(display_name, sid), type: :hash do |_, scope, value|
    x, y = value
    scope.merge(
        # some active record relation
    )
end
```

原則としてmergeはそれぞれのリレーションたちをAND条件で結合していきます。

ではORを作りたいときはというとmergeに渡す前にorを作ります

[ActiveRecord の or は merge とセットで使え - Qiita](https://qiita.com/hirohero/items/8194b8012b9a5f6e592e)

さて、意図せずORになってしまうことがあります。どういうことでしょうか？

`child model`

```ruby
class FooChild < ActiveRecord::Base
    belongs_to :foo_parents, foreign_key: :foo_child_id

    scope :x ->(word) { where('child.x like ?', "%#{word}%")}
    scope :y ->(word) { where('child.y like ?', "%#{word}%")}
end
```

`parent model`

```ruby
class FooParent < ActiveRecord::Base
    has_many :foo_chilren, :dependent => :destroy, :foreign_key => :foo_child_id

    scope :x ->(word) { where(id: FooChild.x(word).pluck(:foo_child_id))}
    scope :y ->(word) { where(id: FooChild.y(word).pluck(:foo_child_id))}
end
```

`controller`

```ruby
class FooController < ApplicationController
   has_scope :x, allow_blank: true, do |_, scope, value|
       scope.merge(FooParent.x(value)) 
   end
   has_scope :y, allow_blank: true, do |_, scope, value|
       scope.merge(FooParent.y(value)) 
   end
end
```

ここで`x=aaa&y=bbb`というリクエストが来た時、x, yでの絞り込みの**OR検索**となります。

ポイントは`where(id: xxx)`の部分です。mergeしたときに2箇所でのidの指定の和集合を取ったものをSQLとして組み立ててしまうのです。

あまりいい解決策が浮かびませんでしたが一つはhas_scopeではhashとして受け取り、愚直にifを書いて分岐する方法です。

`parent model`

```ruby
class FooParent < ActiveRecord::Base
    has_many :foo_chilren, :dependent => :destroy, :foreign_key => :foo_child_id

    scope :p lambda { |x, y|
        if x && y
            ids = FooChild
                  .x(x)
                  .y(y)
                  .pluck(:foo_child_id)
            where(id: ids)
        elsif x
            ids = FooChild
                  .x(x)
                  .pluck(:foo_child_id)
            where(id: ids)
        elsif y
            ids = FooChild
                  .y(y)
                  .pluck(:foo_child_id)
            where(id: ids)
        end
    }
end
```

`controller`

```ruby
class FooController < ApplicationController
   has_scope :p, using: %i(x, y), type: :hash, do |_, scope, value|
       x, y = value
       scope.merge(FooParent.p(x, y)) 
   end
end
```

- [RailsのActiveRecordのmergeメソッドを使ってみる - その辺にいるWebエンジニアの備忘録](https://kossy-web-engineer.hatenablog.com/entry/2020/10/10/190156)
- [Rails の scope をあまり使わない方がいい理由 - ハトネコエ Web がくしゅうちょう](https://nekonenene.hatenablog.com/entry/do-not-use-rails-scope)
- [Railsでよく利用する、Scopeの使い方。 - Qiita](https://qiita.com/ngron/items/14a39ce62c9d30bf3ac3)

### activeredord-import

複数のレコードを追加することを考えるとき、何回も`INSERT`文を発行するのは効率が悪そうだということは言われればまあ納得できると思います。一つの文にまとめて発行することを`BULK INSERT`と呼びます。

Rails6では`insert_all`というメソッドがありこれを実現できるのですがそれ以前の環境や一部のユースケースには`activeredord-import`を用います。

[zdennis/activerecord-import: A library for bulk insertion of data into your database using ActiveRecord.](https://github.com/zdennis/activerecord-import)

ただしMySQLでは親子関係にあるとき子要素を自動で追加しません。また追加した要素を返してくれたりもしないので自力でなんとかする必要があります

つまり`where`でうまく絞り直して取ってくる必要があるわけですがなかなか骨です

- [Rails 6のB面に隠れている地味にうれしい機能たち（翻訳）｜TechRacho by BPS株式会社](https://techracho.bpsinc.jp/hachi8833/2021_07_19/74562)
- [(初心者向け)activerecord-importの使い方 - Qiita](https://qiita.com/makicamel/items/b6d4f3d2661fc66103ed)
- [RubyonRails:activerecord-importを使って複数レコードを一括登録する(BULK INSERT) - Madogiwa Blog](https://madogiwa0124.hatenablog.com/entry/2018/04/21/234242)

#### `where(id: before_id..after_id)`

`BULK INSERT`によって新規レコードが追加されるとき、そのidは連続するはずです。ということは追加前後のidを記録しておけば良さそうです。

- [BULK INSERTの戻り値にPRIMARY KEYは返らない（activerecord-import） - Qiita](https://qiita.com/yn-misaki/items/4e0c86945f51eb4d6067)
- [MySQL - [Rails] activerecord-importを使用したバルクインサートで親子モデルの同時保存｜teratail](https://teratail.com/questions/38938)

whereで持ってこれたらあとはそれを使って子テーブルのレコードに親を指定してあげればいいですね。

#### 親テーブルのレコードは変わらないがそれに紐づく子テーブルのレコードが増える場合

この場合次のような戦略を取ることが考えられます

1. 予め紐づく親テーブルのレコードのhashを取っておく
2. 親テーブルに`BULK INSERT`
3. 親テーブルのレコード全件を取り直しそれぞれのhashを取る
4. 子テーブルに追加するレコードたちを1で取得しておいたhashを元に紐付ける
5. 子テーブルに`BULK INSERT`

予め紐づく親テーブルのレコードのhashを取っておくというのは、子テーブルを仮に`FooElement`とすると次のように`attr_accessor`を書いておいて、

```ruby
class FooElement < ActiveRecord::Base
    belongs_to :foo, class_name: "XxxFoo", foreign_key: :foo_id
    attr_accessor :foo_values
end
```

こういう感じのイメージになる

```ruby
# Fooテーブルのカラムのうち識別するに十分なカラムたち
FOO_ATTRIBUTES = [:bar1, :bar2]

def store(asset, props)
    foos = # do somethig
    foo_records = []
    foo_element_records = []
    foo_ids = asset.foos.pluck(:id)
    element_destroy = FooElement.where(foo_id: foo_ids).each_with_object({}) do |element, hash|
        # do something
    end
    
    # create foo_records
    
    foos.each do |foo|
        foo[:elements]&.each do |e|
            element = element_destroy.delete(
                # something
            )
            element ||= FooElement.new
            
            # copy e to element
            
            # 1. 予め紐づく親テーブルのレコードのhashを取っておく
            foo_values = serialize_foo_values(foo)
            element.foo_values = foo_values
            foo_element_records << element if element.changed?
        end
    end
    
    # do something
    
    ActiveRecord::Base.transaction do
        # 2. 親テーブルに`BULK INSERT`
        asset.foos.import foo_records
        
        # 3. 親テーブルのレコード全件を取り直しそれぞれのhashを取る
        imported_foos = build_values_hash_table(asset.foos.reload)
        # 4. 子テーブルに追加するレコードたちを1で取得しておいたhashを元に紐付ける
        foo_element_records.each do |e|
          e.foo = imported_installed_applications[e.foo_values]
        end
        # 5. 子テーブルに`BULK INSERT`
        FooElement.import foo_element_records
    end
end
def build_values_hash_table(foos)
    foos.each_with_object({}) do |foo, hash|
        item_values = serialize_foo_values(foo)
        normalize_attributes!(item_values)
        hash[item_values] = foo
    end
  end
end

def serialize_foo_values(foo)
  FOO_ATTRIBUTES.map { |attr| foo.send(attr) }
end
```

- [Module#attr_accessor (Ruby 3.0.0 リファレンスマニュアル)](https://docs.ruby-lang.org/ja/latest/method/Module/i/attr_accessor.html)

### migration

テーブルを追加したりカラムを足したりするとき、migrationファイルを作成することで実現できます。

まずは公式のガイドをよく読むことが大事です。

[Active Record マイグレーション - Railsガイド](https://railsguides.jp/active_record_migrations.html)

```
rails generate migration AddPartNumberToProducts part_number:string
```

```ruby
class AddPartNumberToProducts < ActiveRecord::Migration
  def change
    add_column :products, :part_number, :string
  end
end
```

のように簡単なマイグレーションであればコマンドだけで自動生成できます。

カラム名、型、既定値、null制約に注意して定義します。整数型であってもnull制約は意味を持ちます。

マイグレーションファイルを追加するときは必ずup→down→upの確認をしましょう。downに不備があって再度upできないということがあってはまずいです。

- [rails generate migrationコマンドまとめ - Qiita](https://qiita.com/zaru/items/cde2c46b6126867a1a64)
- [railsのカラム追加、削除、データ型変更の方法 - Qiita](https://qiita.com/isaatsu0131/items/e17d11db39745a8f64b0#%E3%82%AB%E3%83%A9%E3%83%A0%E3%82%92%E8%BF%BD%E5%8A%A0%E3%81%97%E3%81%9F%E3%81%84%E6%99%82)
- [【Rails・MySQL】MySQLのデータ型とRailsのマイグレーションファイルのデータ定義の対応まとめ - Qiita](https://qiita.com/vermilionfog/items/816fa7de1d0213979929)
- [Railsでの複数カラムの追加・削除とまとめて行う方法 - Qiita](https://qiita.com/kidokoro-syusei/items/f52d6befd51ceac980e7)
- [MySQL | CHAR型とVARCHAR型](https://www.dbonline.jp/mysql/type/index3.html)
    - limitをかけた文字列カラムにlimit以上の物を入れたらどうなるか

#### bigint対応

Rails5では既定でidはbigintですが、Rails4ではそうではありません

idをbigintにする方法は色々ありますが、いろいろバグもあったようなのでSQLを直書きするのが安心できます。テーブル追加と同時にやる例です。`change`ではなく`up`/`down`で書くと良いでしょう。

```ruby
class CreateFooElements < ActiveRecord::Migration
    def up
        create_table :foo_elements do |t|
            t.string :bar1, null: false
            
            t.timestamps null: false
        end
        
        execute "ALTER TABLE `foo_elements` MODIFY `id` BIGINT NOT NULL AUTO_INCREMENT;"
    end
    def down
        drop_table :foo_elements
    end
end
```

- [Ruby on RailsでシステムIDをbigint型に変更する](https://programming-beginner-zeroichi.jp/articles/157)
- [Add bigint primary key support for MySQL. by kamipo · Pull Request #18220 · rails/rails](https://github.com/rails/rails/pull/18220)
- [rails で id を BIGINT 型 + primary key + AUTO_INCREMENT する - scramble cadenza](https://mgi.hatenablog.com/entry/2015/03/29/191550)
- [Rails5.1からidカラムがbigintになるのでその対応 - koukiblog](https://kamihikouki.hatenablog.com/entry/2017/04/11/141447)
- [drop_table | Railsドキュメント](https://railsdoc.com/page/drop_table)

なお余談ですが次のようにマイグレファイルがなっているとき、何事もなくdownに成功してその後のupでコケます

```ruby
class CreateFooElements < ActiveRecord::Migration
    # 前略
    # def defしてるのに何故か何事もなく通過！！！
    def def down
        drop_table :foo_elements
    end
end
```

#### `t.reference`

他のテーブルの子テーブルとなるようなときなどに外部キーを使うと思うのですがそれを作る多分一番簡単な方法です。`add_foreign_key`/`remove_foreign_key`する手法もあるようですが面倒に見えます。

```ruby
class CreateFooElements < ActiveRecord::Migration
    def up
        create_table :foo_elements do |t|
            t.reference :foo, type: :bitint, index: { name: 'foo_elements_on_foo_id' }
            t.string :bar1, null: false
            
            t.timestamps null: false
        end
        
        execute "ALTER TABLE `foo_elements` MODIFY `id` BIGINT NOT NULL AUTO_INCREMENT;"
    end
    def down
        drop_table :foo_elements
    end
end
```

- [references | Railsドキュメント](https://railsdoc.com/page/references)
- [【Rails】外部キー追加におけるreference型の使用、未使用の違い。外部キー制約によるエラーをコンソールで確認してみた。 - Qiita](https://qiita.com/kents1002/items/661605753a5f6c56ffc3)
- [migration時のreferencesで作成されるindex nameを変更したい [Rails] - Qiita](https://qiita.com/yoshixj/items/73113c7da2bfc61a64c7)
    - `index: { name: }`の解説
- [[Rails]referencesを使用した外部キー設定で沼った - Qiita](https://qiita.com/Jwataru/items/7b840be38d4279224245)
    - 型に注意が必要
- [Rails の migration で外部キー制約の設定をする (add_foreign_key, remove_foreign_key) - Qiita](https://qiita.com/ymneet/items/c09e9b6d1e937a81a389)

### アソシエーション

まずはこれを読みましょう

[belongs_to/has_one/has_manyの簡単まとめ | 酒と涙とRubyとRailsと](https://morizyun.github.io/ruby/active-record-belongs-to-has-one-has-many.html)

一応その他関連資料

- [Active Record の関連付け - Railsガイド](https://railsguides.jp/association_basics.html)
- [[初心者向け] Railsで関連するデータ(親子関係)を保存する方法あれこれ - Qiita](https://qiita.com/jnchito/items/7f41ff3df900909952db)
- [【初心者向け】丁寧すぎるRails『アソシエーション』チュートリアル【幾ら何でも】【完璧にわかる】🎸 - Qiita](https://qiita.com/kazukimatsumoto/items/14bdff681ec5ddac26d1)
- [アソシエーションにおけるclass_nameの定義！ - Qiita](https://qiita.com/wacker8818/items/eccdf0a63616feb14a70)
- [railsアソシエーションオプションのメモ - Qiita](https://qiita.com/tomoharutt/items/e548186c763079327ed1)
- [Ruby on Rails - has_many関係にあるテーブルの値をビューで呼び出し｜teratail](https://teratail.com/questions/19465)
- [grouping - Rails has_many association count child rows - Stack Overflow](https://stackoverflow.com/questions/796150/rails-has-many-association-count-child-rows)

#### 親子関係の設定

親子関係はもともとそういう関係が成立してDBに入っている場合を除けば、自分で設定するものです。なぜならば親レコードの`id`がわからないと子レコードの外部キーにそれを設定できないからです。

```ruby
foo = Foo.create(bar: "aaa")

# 外部キーにid指定してしまうとidの有効性を検証するためにSELECTが走るのであんまりよくない
# element = FooElement.create(bar1: "aaaa", foo_id: foo.id)

# これならレコードがあることはわかってるのでSELECTは走らない
element = FooElement.create(bar1: "aaaa", foo: foo) # belongs_to :foo, ...
```
- [railsのbelongs_toとhas_manyとreferencesの使い方について整理する - 巨人の足元でたじlog](https://my0shym.hatenablog.com/entry/2018/07/19/003625)

```ruby
elements = []

element = FooElement.new
# これならレコードがあることはわかってるのでSELECTは走らない
element.foo = # すでにcreate/saveされるなどしてDBにいるレコードを代入
elements << element

# activerecord-import
FooElement.import elements
```



#### 親テーブルのレコードから紐づく子テーブルのレコードにアクセスする

```ruby
# 直接
foo.foo_elements

# どこかでidが求まってたとして
foo_id = # something
FooElements.where(foo_id: foo_id)
```

#### 子テーブルのレコードから紐づく親テーブルのレコードにアクセスする

`belongs_to`で指定した名前でアクセスする

```
foo_element.foo
```

## Rspec

RspecはRubyにおけるテストフレームワークです。他にRailsにくっついてくる[Minitest](https://qiita.com/sei_sato/items/335a2dec9539307e65c6)ってのも人気のようですが今回はRspecを取り扱います。


### テストとは

[C++初心者のみんな、単体テストとCIを組めるようになって君もライブラリ製作者の仲間入りしよう！#どんな検査を書けばいいのか？](https://qiita.com/yumetodo/items/5886b2c0c421c24c909b#%E3%81%A9%E3%82%93%E3%81%AA%E6%A4%9C%E6%9F%BB%E3%82%92%E6%9B%B8%E3%81%91%E3%81%B0%E3%81%84%E3%81%84%E3%81%AE%E3%81%8B)の焼き直しになりますが改めて。

すべてのプログラムには少なくとも

- 入力
- 出力

この2つがあるはずです。また場合によっては

- 事前状態
- 事後状態

なんかもあるかもしれません。まあこれも広義の意味で入力と出力と言えるので隠れた入出力といったりします。

テストを書くときはこの入力に対して期待する出力が得られるかを検査することになるわけです。

> [新人プログラマに知っておいてもらいたい人類がオブジェクト指向を手に入れるまでの軌跡](https://qiita.com/hirokidaichi/items/591ad96ab12938878fe1)
>
> ![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.amazonaws.com%2F0%2F35671%2F04cb4681-c28e-5f35-5fba-6f6fb45c0b61.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&w=1400&fit=max&s=31d015b0ce94d84eba1df92f8a8b79e1)

### どのようなテストであるべきか

言語分野問わず言えそうなこととしては次のようなことでしょうか

- **すべての条件分岐を通るように検査する**
  - 特定のルートだけ検査したのでは不十分
- 例外が投げられる入力を与える検査をする
  - 意図した例外を投げているかは調べ忘れやすい
- 条件分岐の境界値になるような入力を与える検査をする
  - 「以下」と「未満」を間違えたりド・モルガンの法則をど忘れするのはよくあるミスなので境界値を与えることで効率よくバグが見つかる
- 時間がかかりすぎる検査は可能ならば避ける
  - 時間がかかるテストは誰も実行しない
- そのテストがある理由がわかるように記述されている
  - 理解不能なテストは機能追加やリファクタリングの妨げになる

またRailsのテストという文脈ということでは次のようなことも言えそうです

- DBを操作するテストで過度にテストケースが細分化されていないか
  - テストケースごとにDBがロールバックするようになっている場合、この操作はとても時間がかかる
- レコードの作成/更新時刻に依存するテストの場合時刻を入力で明示しているか
  - 作成時刻がたまたまおなじになったり時刻同期で時刻が逆転したりするとテストが不安定になる

- DRYしようとしていないか
  - DRYするとかえってテストの可読性を落とす
  - テストの数が多くなるとついDRYしたくなるが心を強く持つ(でも負ける)
- 過度に階層化されていないか
    - `describe`/`context`を入れ子にし過ぎになりがちではありますがそんなにいる？っていうことを心がけましょう

### テスト観点をどう出すか

- **要件定義/設計を何度も見る**
    - 仕様を満たすようにテストするという大原則
- 過去の類似機能のテストを見る
- 人を増やす
    - **検証の人に聞いてみる**
    - 強い人に見てもらう
- 過去の検証項目を参考にする
- 1日くらい寝かして明日の私のちからを借りる
- 実働を見る
- (ユーザーの声を見る)

### Rspecをやるときにまず読むべき資料

- [使えるRSpec入門・その1「RSpecの基本的な構文や便利な機能を理解する」 - Qiita](https://qiita.com/jnchito/items/42193d066bd61c740612)
- [使えるRSpec入門・その2「使用頻度の高いマッチャを使いこなす」 - Qiita](https://qiita.com/jnchito/items/2e79a1abe7cd8214caa5)

とりあえずこれを隅から隅まで読めば最低限かけるようになります。

その他参考文献。とりあえずjnchitoさんの記事を探せばいいという感はある。

- [サヨナラBetter Specs!? 雑で気楽なRSpecのススメ - Qiita](https://qiita.com/jnchito/items/a90b3b09d008227d3d60)
- [使えるRSpec入門・その3「ゼロからわかるモック（mock）を使ったテストの書き方」 - Qiita](https://qiita.com/jnchito/items/640f17e124ab263a54dd)
- [使えるRSpec入門・その4「どんなブラウザ操作も自由自在！逆引きCapybara大辞典」 - Qiita](https://qiita.com/jnchito/items/607f956263c38a5fec24)
- [実用的な新機能が盛りだくさん！RSpec 3.3 完全ガイド - Qiita](https://qiita.com/jnchito/items/3a590480ee291a70027c)
- [RSpecのletの遅延評価を利用してよりコンテクスチュアルなSpecを書く – もばらぶエンジニアブログ](https://engineering.mobalab.net/2018/12/28/rspec%E3%81%AElet%E3%81%AE%E9%81%85%E5%BB%B6%E8%A9%95%E4%BE%A1%E3%82%92%E5%88%A9%E7%94%A8%E3%81%97%E3%81%A6%E3%82%88%E3%82%8A%E3%82%B3%E3%83%B3%E3%83%86%E3%82%AF%E3%82%B9%E3%83%81%E3%83%A5%E3%82%A2/)
- [RSpecの実行時間を1/5にした話 - Speaker Deck](https://speakerdeck.com/ham0215/5nisitahua?slide=10)
- [performance testing - How much time does "let" really save in RSpec tests? - Stack Overflow](https://stackoverflow.com/questions/53962748/how-much-time-does-let-really-save-in-rspec-tests)
- [【RSpec】配列要素全てにマッチャを適用する - Augmented Usamimi](https://izumin.hateblo.jp/entry/2015/02/09/234519)
- [`all` matcher - Built in matchers - RSpec Expectations - RSpec - Relish](https://relishapp.com/rspec/rspec-expectations/docs/built-in-matchers/all-matcher)
- [RSpec - expectの中を汚さずに複雑な検証ができるsatisfyマッチャがすごい - Qiita](https://qiita.com/ishidamakot/items/a23b86b9f59ab8e4fbb1)
- [【RSpec】described_classについて - Qiita](https://qiita.com/mightysosuke/items/c7c00dcbaae3ba5f6734)

### 他の言語のテストフレームワークと比較したときのRspec

生粋のRspec使い達からは異論もたくさんあろうかと思うのですが、他の言語のテストフレームワークに慣れ親しんだ人視点です。

テストフレームワークごとに多少色が出るのはそういうものだと思いますが、あんまりにも違うとびっくりしてしまいます。

まあでも独自路線を突っ走ってしまうのってC++でもあるので(template多用するやつとか)わからなくはないですね？

- 階層化しすぎになりがち
    - JavaScript界隈のJestなんかも同様の階層化ができますが、`subject`との組み合わせもあるのかやたら階層化が深くなりがち
- `let`が乱舞する
    - 悪いってわけではない
    - ただこれによって独特の世界観が作られている気もする
    - 上層のletを上書きとかもできるが多用すると可読性を落とす
    - `it_behaves_like`したいときは使わざるを得ないですよね・・・~~引数とかないんですか~~
- `subject`/`before`/`let`全部見ないと前提条件がわからない
    - 言い換えるとそこだけ見ればわかるということもできるが・・・
    - なんでもかんでも`subject`を使いすぎ
        - `subject { super()[:foo] }`して`is_expected`を使おうとするのはどう考えてもオーバーキル
            - `expected(subject[:foo])`でいいのでは？
        - ~~むしろ`subject`/`before`滅ぼしませんか？~~
- `it`の中をシンプルにしようとしすぎる
    - `it`が一行に書けると英文っぽく読めるという理論はわからなくないが・・・
    - べつに`it`の中に複数のテストがあってもいいのでは？
        - `aggregate_failures`(Rspec >= 3.3)をつかうともっと便利
        - [実用的な新機能が盛りだくさん！RSpec 3.3 完全ガイド - Qiita#1. 特定のエクスペクテーション群をまとめて検証できる（aggregate_failures メソッド）](https://qiita.com/jnchito/items/3a590480ee291a70027c#1-%E7%89%B9%E5%AE%9A%E3%81%AE%E3%82%A8%E3%82%AF%E3%82%B9%E3%83%9A%E3%82%AF%E3%83%86%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E7%BE%A4%E3%82%92%E3%81%BE%E3%81%A8%E3%82%81%E3%81%A6%E6%A4%9C%E8%A8%BC%E3%81%A7%E3%81%8D%E3%82%8Baggregate_failures-%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89)
    - `it`をシンプルにしようとしすぎるあまりに`let`とか`subject`が増殖するのは本末転倒では？
        - 何事もバランスが大事
    - DB操作は`it`単位でロールバックするので`it`の数が増えるとテストが遅くなる
        - これは`database_cleaner`ごと外せるならまあ関係ない
        - [Railsアプリからdatabase_cleanerを外したらRSpecが30%速くなった話 - Qiita](https://qiita.com/ham0215/items/7516117df87d2631e31d)

いろいろ書きましたが周辺コードと空気感を合わせて書くのがいいとは思います。

### `subject`の用法・用量

[Rspecのchangeマッチャーを使う時、初期状態の設定をsubjectでやるのってありですか？ - Qiita](https://qiita.com/yumetodo/items/cd1fca4e4e56f573e9a2#comment-4026708af1bd356a8005)

という記事を書いたときの反響が勉強になったので引っ張っておきます。

> https://qiita.com/yumetodo/items/cd1fca4e4e56f573e9a2#comment-4026708af1bd356a8005
>
> @jnchito 2021-08-07 07:37
>
> @yumetodo さん、こんにちは。
RSpecの書き方はいろんな流派（？）がありますが、僕個人としては滅多にsubjectを使いません。
少なくともsubjectが向いているのは、以下の例のように副作用がなく、一定の入力に対して常に一定の値を返す関数的な処理です。
>
> ```ruby
> describe Person do
>  let(:user) { User.new(age: age) }
>   # adult?メソッドには副作用がなく、ageの値に応じて常に一定の真偽値を返す
>   subject { user.adult? }
>   context '20歳未満' do
>     let(:age) { 19 }
>     it { is_expected.to be_falsey }
>   end
>   context '20歳以上' do
>     let(:age) { 20 }
>     it { is_expected.to be_truthy }
>   end
> end
> ```
>
> 本記事のコードのように、副作用の結果を期待する処理をsubjectにしようとするといろいろと無理が生じます。（にもかかわらず、何が何でもsubjectにしたい派の人たちは、そういう処理もsubjectを使おうとしてテストコードに無駄な工数をかけようとするんですよね。いくら頑張っても結局トリッキーなテストコードしか出来上がらないのに…

> https://gamelinks007.net/@S_H_/106709170737688666
>
>@S_H_@gamelinks007.net 2021年8月6日 21:25 
>
> @yumetodo 
minitest派なのであんまり知見があるわけではないですが、素直にletとか使う方が良いかなと
>
> 理由としてはそう書いてる人が多く、あとから引き継ぐ時に楽だからですね
>
> あと、describeにある程度のテストをまとめた方が良いからという判断もありますね
>
> @yumetodo 
なのでsubject自体を使わずにRefinementsとかでそのスコープでだけ有効なメソッド生やすとかが楽だし、読みやすいかなと
>
> @S_H_ なるほど
>
> たしかにsubjectつかうとdescribeが小さくなりすぎがちというのはわかる気がする
>
> @yumetodo 
ですねー
なので、ちょっとそのテストフレームワークから離れるときはModuleとかで便利そうなメソッドを切り出すとかすると良さげですね

またご紹介いただいた記事も非常に参考になります。

[【翻訳】RSpecのリードメンテナだけど何か質問ある？ - Qiita](https://qiita.com/jnchito/items/3a8d19fd9a30468cafd4)

### Structが便利なこともある

ActiveRecordで各カラムにアクセスするときって`Foo.bar`みたいにアクセスすると思います。そしてそういうデータ型を受け取る関数を書くこともあるでしょう。当然それのテストを書きますよね？

ところがRubyで書きやすいデータ構造ってHashなんですよね。テストの期待結果を作ったりするのにこの構造をほしいためだけにわざわざ後述のFactoryBotを使ってテストデータ作るのはオーバーキルです。

これを実現する方法として[`class.new`で頑張る](https://secret-garden.hatenablog.com/entry/2015/05/30/000000)方法もあるのですが面倒です。  
[`OpenStruct`をつかう例もあるようですが](https://madogiwa0124.hatenablog.com/entry/2019/07/21/153114)もっと高速でミニマムな方法があります。

それが[Struct](https://docs.ruby-lang.org/ja/latest/class/Struct.html)です。

[めっちゃ便利なRubyのStructクラスのお話 - Qiita](https://qiita.com/ex_SOUL/items/696b3ac2869a2f71f3c0)

つまりこんなふうに使えます(letを多用しすぎているかもしれない)。

```ruby
def some_method(elements)
    elements&.map { |e| e.bar1 }.join || ""
end
```

```ruby
describe "arikitari na test" do
    let(:element) { Struct.new(:bar1) }
    let(:actual) { some_method(raw_elements&.map { |e| element.new(e) }) }
    context "single" do
        let(:raw_elements) { ["hoge1"] }
        
        it { expect(actual).to eq "hoge1" }
    end
    context "mutiple" do
        let(:raw_elements) { ["hoge1", "hoge2"] }
        
        it { expect(actual).to eq "hoge1,hoge2" }
    end
end
```

> @S_H_@gamelinks007.net 7月27日
>
> Structを簡単に書けるようにしようぜってチケットならこないだ出たね
>
> [Feature #16986: Anonymous Struct literal - Ruby master - Ruby Issue Tracking System](https://bugs.ruby-lang.org/issues/16986)

## test用のデータをDBに入れるには: FactoryBot(旧FactoryGirl)


かつてFactoryGirlと呼ばれていたものは現在ではFactoryBotと名前を変えています。FactoryBotでもFactoryGirlでもどっちでもいいわけですがそもそもこれは何をするためのものなのでしょうか？

> [Rails テスティングガイド - Railsガイド#4.2 フィクスチャのしくみ](https://railsguides.jp/testing.html#%E3%83%95%E3%82%A3%E3%82%AF%E3%82%B9%E3%83%81%E3%83%A3%E3%81%AE%E3%81%97%E3%81%8F%E3%81%BF)
>
>よいテストを作成するにはよいテストデータを準備する必要があることを理解しておく必要があります

FactoryBotはテストデータを作るための支援をしてくれます。  
もっとも簡易的な使用方法は各カラムにデフォルト値を入れておくことです。  
しかし、よく設計されたテストデータが作れたとき、それはいくつものテストケースをまたいで利用する価値があるはずです。

### factoryファイルを記述する

各カラムのデフォルト値設定場所となりがちな気もしますが、意図としてはテストケースをまたいで利用する価値があるテストデータ設定場所です。

```ruby
FactoryBot.define do
    factory :foo, class: Foo do
        bar { 'hoge' }
    end
    factory :foo_element, class FooElement do
        bar1 { 'hoge1' }
        trait :with_dependents do |e|
            foo
        end
    end
end
```

- [FactoryBot(FactoryGirl)チートシート - Qiita](https://qiita.com/morrr/items/f1d3ac46b029ccddd017)
- [FactoryBot 入門 [翻訳][Railsの場合まとめ] - Qiita](https://qiita.com/andmorefine/items/a51fda98a0baeb4b89fa)
- [FactoryBotを使う時に覚えておきたい、たった5つのこと - Qiita](https://qiita.com/piggydev/items/32717b6c382272e2134e)
- [FactoryGirlでtraitを使うとintegration test書くのが捗るという話｜TechRacho by BPS株式会社](https://techracho.bpsinc.jp/morimorihoge/2013_08_23/12744)

### create/build

レコードを作成して実際にDBに入れるときは`FactoryBot.create`(旧: `FactoryGirl.create`)を用います。  
modelを指定する第1引数にはmodel名をスネークケースにしたもののSymbolやfactoryファイルで指定した名前が利用できます。

```ruby
FactoryGirl.create(:foo_element, :with_dependents)
```

同様にしてレコードを作成するだけのときは`FactoryBot.build`が利用できます。

```ruby
FactoryGirl.build(:foo_element, foo)
```

なおfactoryファイルの恩恵を受けなくていいなら、ActiveRecordのものを使っても問題ない気がします。

```ruby
foo.foo_elements.build(hoge)
```

親子関係は上記のように通常のActiveRecordでの操作と変わるところはなく、create/saveするなどして実際にDBにデータが入っているレコードを用いて指定することで作成できます。

- [世界一やさしいFactoryGirlの使い方:入門編 - Qiita](https://qiita.com/9_tricks/items/f333a76bcf7f90f85144)
- [FactoryBot（旧FactoryGirl）で関連データを同時に生成する方法いろいろ - Qiita](https://qiita.com/metheglin/items/47116ccbdb26aa00e034)

### N+1 insertを避けてレコードをたくさん作る: create_list死すべし、慈悲はない(?)

すでに上で述べている通り、実行速度の遅いテストはいずれ廃れて実行されなくなる運命にありますし、開発効率を落とします。つまりN+1問題はテストにおいても撲滅されなければなりません。

レコードをたくさん作るとき、`create_list`が用いられることがあります。

```ruby
FactoryGirl.create_list(:foo_element, 10, foo: foo)
```

これが何を引き起こすかというとなんと`INSERT`文が10回発行されます。

これはよろしくないですね。代わりに`build_list`とactiverecord-importを使います。

```ruby
elements = FactoryGirl.build_list(:foo_element, 10, foo: foo)
FooElement.import elements
```

ただし`create_list`は生成物の配列を返すので`build_list`のときと違っていちいちDBを読みに行かなくてもいいという利点もあるのでいつでも置き換えればいいというものでもなさそうです。

create_listに限らず、create/save系のご利用は計画的に！

- [FactoryBotで高速に大量データを作る方法 - Qiita](https://qiita.com/ham0215/items/dad6f5d3d63bd498d999)
- [世界一やさしいFactoryGirlの使い方:入門編 - Qiita](https://qiita.com/9_tricks/items/f333a76bcf7f90f85144)
- [RSpecでFactoryBotから複数のインスタンスをまとめて作成する【create_listを使用】 - Qiita](https://qiita.com/kodai_0122/items/e755a128f1dade3f53c6)
- [Factorybotでデータの配列を作る - n350071のブログ](https://n350071.com/factorybot-create-list/)
- [FactoryGirlで連番を使う - Qiita](https://qiita.com/hogeta_/items/ad9bf4490ef0b67caf60)