OmniAICreator/Qiita-1.07M huggingface dataset:
Rails×Reactアプリをクローンした後の環境構築について。



Rails×Reactで構成されたアプリケーションに対して git clone した後、環境構築しようとした際に、ものすごく時間がかかったので、同じミスをしないようにメモしておく。

# 結論
()は必要に応じて

① Nodeのバージョンを指定
(② .nvmrcに希望のバージョンを指定)
(③ .gitignoreに .nvmrcを追加)
④ gemfile.lock削除
⑤ Railsのバージョンを指定
⑥ ``Bundle install``
⑦ ``Rails db:create``
⑧ ``Rails db:migrate``
⑨ ``npm ci``
⑩ ``yarn -v``(→ yarnがインストールされていなければ ``yarn install``)
( ``rails webpacker:compile``)


### ①について
まずlatestなNodeを使用するとnode-gypのエラーが後々発生する可能性があるので、出来ればstableなバージョンをインストールして使用するべき。
(npmは基本自動で変更されるので合わせる必要なし)

### ②について
筆者は、Nodeバージョン管理にnvmを使用していたので以下のHPを参考にした。
引用：https://shinshin86.hateblo.jp/entry/2020/05/14/220149

### ③について
今後gitでマージする際に、.nvmrcファイルをアップロードしないように、以下のソースコードをプロジェクト内の.gitignoreファイルに追加。

```ruby:.gitignore
/.nvmrc
```

### ④について
基本的にGemfile.lockを削除することは、__基本的にNG__。
だが、筆者がクローンしたプロジェクトは、__mimemagic <= 0.3.5に依存している__Railsアプリであったため、どうしても⑤のbundle installに失敗してしまっていた。
以下のHP上での、「都合によりRailsをアップデートできない・したくない場合の操作」を実行しても、どうしても上手くいかなかったため、
④→⑤の流れをするとなぜか上手くいった。
引用：https://hackmd.io/@mametter/mimemagic-info-ja

### ⑤について
Gemfileにrailsのバージョンを指定。

### ⑨について
``npm ci``とは。
package-lock.json から依存関係をインストールするコマンド。
既に node_modules フォルダの中身があっても一旦削除してくれる。
依存関係の更新をせずに整合性チェックと依存パッケージのダウンロードのみを行い、 npm install より高速に動作し、CIで必要なことだけを行うのが、このコマンドである。
__nodeを使用しているプロジェクトをgit cloneするときは、必ず必要になるコマンド__
引用：https://qiita.com/mstssk/items/8759c71f328cab802670

### ⑩について
ローカルでサーバーを開いたときに、

```
ℹ ｢wdm｣: wait until bundle finished: / ......
```

などが出てきてフロント画面の描画が遅い時などは、このコマンドが必要になる場合がある。
jQueryでタブをクリックすると内容が変化するタブメニューを実装

css

```css:style.css
.nav {
    width: 100%;
    max-width: 600px;
    height : 50px;
    margin: 0 auto;
}
.nav > li {
    list-style: none;
    float: left;
    width: 33.333%;
    background-color: #CCC;
    text-align: center;
    line-height: 50px;
    color: #FFF;
    font-size: 20px;
    border-right: 2px #FFF solid;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
}
.nav > li:last-child {
    border-right: none;
}
.is-hidden {
    display: none;
}
.contents {
    width: 100%;
    max-width: 600px;
    padding: 30px;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
    margin: 0 auto;
    border: 2px #CCC solid;
    border-top: none;
}
.contents > li {
    list-style: none;
}
```

html,jQuery

```html:index.html
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="format-detection" content="telephone=no">
<title></title>
<link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/base.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="wrapper">
    <ul class="nav">
        <li>HOME</li>
        <li>NEWS</li>
        <li>MYPAGE</li>
    </ul>
    <ul class="contents">
        <li>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</li>
        <li class="is-hidden">Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</li>
        <li class="is-hidden">Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</li>
    </ul>
</div>
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript">
// navの小要素であるliをクリックして、contents内の小要素であるli要素を表示させる。
// .index() 要素のindexを取得。
// .eq() 引数に応じたindexの要素を指定。
// .addClass() クラスを追加。
// .removeClass() クラスを削除。
$(function(){
  $(".nav li").click(function(){//navクラスのliをクリックしたらイベントスタート
    var num = $(this).index();//navクラスのliのインデックス番号を取得
    $(".contents li").addClass("is-hidden");//一旦contentsクラスのliにis-hiddenクラスを追加し、全て非表示にする
    $(".contents li").eq(num).removeClass("is-hidden");//eq()でnavクラスのliのインデックス番号を引数に指定し、
//contentsクラスの同じインデックス番号のliのis-hiddenクラスを削除。これで選択したタブと紐ずく内容だけを表示できる
  })
});
</script>
</body>
</html>
```
Hashの配列から任意のキーで抜き出す【Ruby】

## Hashの配列から任意のキーで抜き出す
```
<Hash>
.pluck(:<key1>, :<Key2>, ...)
.map {|<Key1>, <Key2>, ...| {<Key1>: <Key1>, <Key1>: <Key2>, ...}}
````
以下みたいに書ける(Active Recordの場合select使えばいいんですけど)。

````ruby
User
.find(1)
.pluck(:name, :desc)
.map {|n, d| {name: n, desc: d}}
#=> [{name: "a", desc: "This is a"}]
````
DRYに書くとこんなん。keys.zipのとこのkeysだけ変えればキーをすり替えられる。

````ruby
def pluck_by(*keys)
    pluck(*keys).map {|obj| keys.zip(obj).to_h}
end
````
jQueryで簡単なモーダルウィンドウを実装


css

```css:style.css
.modal {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: #000;
}
.modal-content {
    position: fixed;
    top: 50%;
    left: 50%;
    width: 300px;
    height: 300px;
    margin: -150px 0 0 -150px;
    background-color: #fff;
    border-radius: 20px;
}
.modal-text {
    display: table-cell;
    width: 300px;
    height: 300px;
    text-align: center;
    vertical-align: middle;
}
.modal-close {
    position: absolute;
    top: -10px;
    right: -10px;
    width: 30px;
    height: 30px;
    padding-bottom: 4px;
    background-color: #fff;
    border: 2px #777 solid;
    border-radius: 15px;
    color: #777;
    font-weight: bold;
    -webkit-box-sizing: border-box;
    box-sizing: border-box;
}
.modal-show {
    margin: 50px;
}
```

htmlとjQuery

```html:index.html
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="format-detection" content="telephone=no">
<title></title>
<link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/base.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="wrapper">
    <p class="modal-show">CLICK!!</p>
    <div class="modal" style="display: none;">
        <div class="modal-content">
            <div class="modal-text">MODAL WINDOW</div>
            <button type="button" class="modal-close">x</button>
        </div>
    </div>
</div>
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript">
// .modal-show をクリックすることで .modal をfadeInする。
// .modal-close をクリックで .modalがfadeOutする。
$(function(){
  $(".modal-show").click(function(){
    $(".modal").fadeTo(500,0.7);//第一引数に秒数、第二引数にopacityを設定し、その秒数をかけて設定したopacityに変化する。
  });
  $(".modal-close").click(function(){
    $(".modal").fadeOut(500);//一定時間かけてフェードアウトする。
  });
});
</script>
</body>
</html>
```
メモリ不足に陥った際のワークアラウンド

Amazon Web ServicesのEC2で「nano」や「micro」などの低スペックなインスタンスサイズを選択した場合、パッケージのアップデート時、パッチマネージャーからのスキャン時やインストール時にメモリ不足で失敗してしまう事が度々あります。

回避策として有用だったワークアラウンドは以下4点。

# 1. インスタンスタイプを変更
メモリ容量の大きなインスタンスタイプに変更することで事象を回避できる可能性があります。

:::note warn
実際はコストの関係で気軽にインスタンスサイズを上げることは難しいと思います。
:::

# 2. スワップ拡張を実施
スワップ拡張を実施することで事象を回避できる可能性があります。

```bash
$ sudo dd if=/dev/zero of=/swap.extended bs=1M count=512
$ sudo mkswap /swap.extended
$ sudo chmod 0600 /swap.extended
$ sudo swapon /swap.extended
$ sudo echo '/swap.extended swap swap defaults 0 0' >> /etc/fstab # SWAP拡張を永続化したい場合に実行
```

# 3. パッケージ管理ソフトウェアが参照するリポジトリの数を調整
aptやyum、dnfなどのパッケージ管理ソフトウェアで参照するリポジトリの数が多い場合、多くのメモリが必要となりますが、リポジトリの設定数を調整することで事象を回避できる可能性があります。

# 4. パッケージ管理ソフトウェアの設定変更
利用可能なディストリビューションは限られますが、パッケージ管理ソフトウェアのオプション設定を施すことで事象を回避できる可能性があります。
具体的には「/etc/yum.conf」の設定でasyncオプションをFalseで設定します。

:::note warn
デフォルトでパッケージは並列でダウンロードされるため、asyncオプションをFalseで設定することでメモリの使用量を抑えることが可能です。
:::
Jupyter Notebookのカーネルの設定

# はじめに
Jupyter Notebookに仮想環境の設定を反映させるためにカーネルを設定する。

# 環境

```
macOS: Catalina 10.15.7
xCode: version 12.4
```

# カーネルの作成
まずは、任意の仮想環境に入る。

```bash:terminal
$ pyenv activate <name>
```

`pip`を用いて`ipykernel`をインストール。

```bash:terminal
$ pip3 ipykernel
```


他に必要なライブラリをインストール。

```bash:terminal
$ pip3 install jupyter matplotlib numpy pandas scipy scikit-learn　#なんでも良い
```

好きな名前をつけてカーネルを作成する。

```bash:terminal
$ python3 -m ipykernel install --user --name=<name>
```

`jupyter notebook`でブラウザを開いたら、新規作成の際に上で作成したカーネルを選ぶ。必要なライブラリがインストールされた環境で作業を行うことができる。

### カーネルの確認
```bash:terminal
$ jupyter kernelspec list
```

### カーネルの消去
```bash:terminal
$ jupyter kernelspec uninstall <name>
```
備忘録 〜何故わざわざQiitaに登録して、投稿を開始したか〜

## Qiitaに投稿を始めた理由
普段社内向けとかに、ドキュメントを残す癖はつけているが、それをわざわざ時間のコストを割いてQiitaに投稿を始めた理由は以下の４つ。

- アウトプットを発信という形で残すことで、人材価値を上げる。
- ワンチャン誰かからの反応きて、新しい知見とか得られたら嬉しい。
- そのうち自分のHP作りたいモチベが湧いた時のために、記事として貯めておきたい。
- 「社内チーム向けのドキュメント」から、「発信のための記事」という変換において、構造とか言葉使いにどんな差分が出るかを見るのが、面白そうだったから。

<br />
最大の理由は、いちばん上のやつ。
「休日もプログラミングをしてる」って口で言うより、Qiitaのコンスタントな更新を見せる方が楽だし、わかりやすい。

最後のに関しては、いちばん副次的なメリットで、いちばん好奇心が向いているところ笑
自分が箇条書きで書いちゃう癖があるので、それを文章にって変換するの面白そうだなーって感じ。

## そのうちあげる予定の記事
実際に書いたら、忘れてなければ多分ちゃんとリンク貼っときます。
- トラブルシューティングの記録
- 今作っている自作のツールの記録（Electron使って）
- 便利やったパッケージとかツールとかの記録
- 業務を経てなんか感じたこととか

目標：
1. 積み下書きないように、書くのが止まったら、記事のボリュームを少なくして投稿する。
2. サボって投稿期間が開いたら、その間何してたかを軽く残す。
3. 毎週土曜の朝9:00~10:00に、書いて投稿する。
競技プログラミングは就活の役に立つ、が。

# 競技プログラミングは就活の役に立つか
立ちました。
けど、
このスキルは **使い方を間違えると破滅** しそうな雰囲気を感じたので共有します。

### 想定読者
競技プログラミングをしていて、アプリやソフトウェアの開発する会社への就職を目指す人。
なんというか一般的なIT企業だったりベンチャーだったりな所。
（アルゴリズム力を強く問うような会社を除く）
アカデミック、研究職の方面に関してはわからないので触れられません。

### 筆者のスペック
- Atcoder 1800くらい
- 大学に入ってからプログラミングを学ぶ
  - 初手競プロでスキルを付けた
  - 開発は3年になってから手を付けた
- 競技プログラミング部 部長
- ICPC出場経験あり
  - ぼちぼちの成績(台湾で10-20位ぐらい)


## 競技プログラミングがどのように役に立ったか
実際めちゃくちゃ役に立ちました。
少なくとも以下のような点でメリットでした。

#### コーディング試験で落ちない
落ちたことが無いです。
水色以上あれば解けるような問題が多数でした。
ただ、アルゴリズム系の問題ではない、開発力を問うような問題も少数ながら見かけたのでそのあたりは注意です。

#### プログラミングのスキル/意欲の担保
競プロでそれなりのレートを持っていることで、プログラミング自体の実力が担保されました。
コーディング力やアルゴリズム力、意欲を証明するには競プロを出すだけで十分でした。

#### 学生時代に頑張ったこと
これ、 **一番でかい** です。
いわゆる「ガクチカ」ってやつですね。
就活始めるまでこの質問の存在知らなかったのですが、これを考えるときマジで競プロやってて良かった、になりました。
ICPCに出た事、それに向けてチームで頑張ったこと、多少の結果が残せたこと
これは、ガクチカとして語るには十分でした。

## 競技プログラミングがどのように役に立たないか
**メイントピックです**
ここを勘違いすると、間違いなく **破滅** すると思います。
私は就活を始めるまで気が付きませんでした。

#### 即戦力にはなり得ない
即戦力を求めている会社を目指すのであれば、競プロ力だけでは不十分です。
競プロやっているだけでは、即開発出来る人としては捉えてくれません。
競プロ一本で行くのであれば、教育に力を入れている会社を選ぶ方が無難です。

#### エンジニアとしての総合力を担保しない
エンジニアとしての力を測る指標として、競プロ力だけでは不十分です。
足りない点は諸説あるとして、具体的な問題としては開発力の話です。
面接官も一番ここを測るために質問してきます。
例えば、Webアプリケーションフレームワークに関する話だったり、SQLの使い方だったり、設計モデルだったり。

### 要するに
技術力というか、開発力というか、その辺が不足しがちです。
Git、Docker、RDBMS...
面談やら面接やらでは大体問われる。
まぁ、競プロ一本の私は何もわからんわけです。
困った。

## どうしよう
<font color="#f5f5f5">　　　　　　　　リングが動いてる</font>
自分なりの解決法を共有します。

#### アウトプットしよう
自分で何か一つ、開発しましょう。
ジャッジシステム作ったり、PythonでBOT作ってみたり。
それを見せられれば、上記エンジニア力の部分を多少証明できます。
結局見せられる物作るのが、自分が就活した中では最強の補助パーツでした。

オマケに、実際に開発すると自然と開発に掛かる周辺知識が身に付きます。
この辺りの質問は面接で問われがちです。
自分で言うのもなんですが、爆速で身に付きました。
多分、競プロで身に付いた土台があったからこそな気がします。

## 結論
アウトプット、お勧めです。
なんか、競プロに関係するwebアプリ作ろう。


## 例外

#### ポテンシャル
赤コーダーとか橙コーダーレベルだとポテンシャル枠に入り込んでいる例を見かけました。

#### コミュ力
やべえよやべえよ。
必死に面接の準備をして何とかするしかありませんでした。
まじで、準備、大事。毎回数時間かけた。


## ついでに

少し枠から外れる話ですが早めに動くが吉です。
加えて、2年の春休み(2-3月)から動くと、1-1面談イベントにもワンちゃん参加出来て、人事の方との繋がりが作れます。
そこから伝手伝手でインターンに応募しましょう。
早くから動くことで、面接の数をこなせることがまずメリット。
そこの面接で、自分に足りない力が沢山わかりました。
あとコミュ力の問題も解りました。
python: 何これ？set operationを使ったらin operatorより爆速だった。

# 何をしていたか
あるデータベースから1,225,793個のウイルスゲノム配列をダウンロードして解析した。数か月たって、再度データをダウンロードしたところ、2,486,361個に増えていた。処理コードはすでに書いてあって、前回解析済みのものはスキップする仕組みになっている。コードのちょっとした手入れの最中に、思いがけない速度改善を得たのでそれについて書きます。

# 処理コードの概要
ウイルスゲノム配列はfastaファイルとして、また、前回までに解析済みのaccession idは、一行にひとつづつ書きこんだファイルに保存してあり、これらを入力ファイルとして用いる。

コードはこんな感じの作りです。

- 解析済みaccession idをファイルから読み込んでリスト(known_accessions)に格納する
- Bio.SeqIOを用いて、fasta fileから順次配列レコードを読み込んでいき、まずaccessionをとる
- そのaccessionが先のリストになければ次の処理に進む、あれば次のレコードへ

"accessionが先のリストになければ"、というところには単純にin operatorを使いました。

```python
if acc not in known_accessions:
    # do sequence sanity check
    # re-construct id line
    # write seq to fasta file
```
ってな具合に。ちなみに、ファイルへの書き出し部分が速度のボトルネックだということに気が付いたので、ひとつづつ書き出すのではなく、ある程度ため込んでから（例えば5000配列）書き出すようにすることで、ずいぶん速度が上がりました。しかし、今日の要点は、そこではないのです。

# あれ？
最初に気がついたのは、ファイルへの書き出しをさせない状態でのテストで、known_accessionsに短めの、あるいは空のリストを使うとやたら処理が速くなるということでした。え？もしかして`acc not in known_accessions`の評価で時間がかかっている？さすがにリストの長さが100万を超えると目に見えて影響が出る？ちなみにelementはすべて14文字のstrです。

# こうしたら爆速になった
たまたま同じ日に、リスト間で共通するelementの抜き出しをしていて、set operationのスピードに感動していた。そこで、in operatorでやっている部分をset operationに変えたらどうなるか、を試してみた。`if acc not in known_accessions`の部分に該当するsetを使ったバージョンは以下の通り。

```python
if len(set([acc]) & set(known_accessions)) == 0:  # set([acc])は、{acc}でもいいですね
    # あれこれ
```
**速い！**しかも少し、じゃないですよ、めちゃくちゃ速い！実験用コードを書いて、10万のaccessionsをひとつづつ、2,486,361個のelementを含むリスト（setにしていますが)に対して試してみると、0:01:08.563127が0:00:00.445583、興奮してそのまま書いてしまいましたが、1分が0.45秒に！

ちなみに1万のaccessionsで試すと0.73秒が0.41秒で、それほどimpressiveには見えませんが、この数の繰り返しでは、コードの最初で行っている、ファイルからのaccessionの読み出しとリストへの格納が実行時間の大半を占めてしまうからだと思われます。

さて、もともとのコードでは7時間11分かかった本番の処理を、set operationでの評価に書き換えたコードで行ってみると、23分47秒で完了しました。たった一行の書き換えで、ここまでかわるなんて。あれこれ試して半日以上つぶれましたが、今後も繰り返す作業なので、もとはすぐに取れます。今後も精進を続けます。

# まとめ

次のようなifブロックが繰り返し実行されるコードで、

```python
if a in very_big_list:
    # do something

if a not in very_big_list:
    # do something
```
if文の評価に時間がかかっているのかも、と思ったら、

```python
if len({a} & set(very_big_list)) > 0:
    # do something

if len({a} & set(very_big_list)) == 0:
    # do something
```

で改善されるか試してみましょう。
SlackのIncoming Webhooksを試してみた

# やりたいこと

SlackのIncoming Webhooks経由でメッセージを送る。

# 作業ログ

## SlackのIncoming Webhooksを設定

[Slackのドキュメント](https://api.slack.com/messaging/webhooks)を参考に設定する。

### Slack appの作成

ドキュメントの`Create your Slack app`ボタンを押下

![Create a app](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350260/72681b8e-c51e-ebb1-8fc2-94ec731f837a.png)

今回は、`From scratch`の方を試す。
appの名前と、紐付けるworkspaceを指定し、`Create App`を押下する。

![App metadata](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350260/b3826c7f-e2be-e9d5-fd0c-4e11031de846.png)

### Incoming Webhooksの設定

以下Webページにリダイレクトされるので、`Incoming Webhooks`を押下する。

![Basic Information](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350260/2a718f3b-0c66-3ecf-fd08-07c267440e5a.png)

以下ページで`Activate Incoming Webhooks`のトグルを`On`にする。

![Incoming Webhooks](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350260/d7901054-5011-f04e-996c-159cec4cc889.png)

`Webhook URLs for Your Workspace`設定が表示されるので、`Add New Webhook to Workspace`ボタンを押下する。

以下ページに遷移するので、通知を送るチャンネルを指定して、`許可する`を押下する。
![Permission](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350260/39a21420-bb78-8c4a-5550-127983a0838d.png)

以下画像のように、Webhook URLが作成された。

![Token and Webhook URL](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350260/daeede8f-e2e8-a10a-2521-cba232834344.png)

### curlでメッセージをPOSTしてみる

```bash
$ export SLACK_WEBHOOK_URL=<Webhook URL>
$ curl -X POST -H "Content-type: application/json" --data "{'text':'Hello, World!'}" $SLACK_WEBHOOK_URL
ok
```

Slackのチャンネルを確認

![Slack Channel](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350260/a661ed83-eaa2-9ace-bec4-a4e17d3375c8.png)

メッセージの送信ができた!
OpenFOAM 9 チュートリアルケースの動作確認 : 多相流体、interFoam、ダムブレイクでの乱流モデルの違い

# 概要
チュートリアルケースのダムブレイクについて、乱流モデルで層流（laminar）を指定したケースと、乱流（RAS（_k-$\epsilon$_ モデル））を指定したケースのアニメーションの比較を行う。

# アニメーション
<table>
<tr>
<td><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1784513/139e53b2-32ac-78bb-5a12-32164638d03c.png"></td>
<td><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1784513/f50dde5f-68c3-62ca-81ee-049b6fd525fe.png"></td>
</tr>
</table>
validates_uniqueness_ofとは

#はじめに

オリジナルアプリでいいね機能の実装に取り掛かっています。
そのとき初めて出てきた記述があったのでアウトプットしていきます。

#validates_uniqueness_of

いいね機能の実装のために`likeモデル`を作成しました。

```like.rb
class Like < ApplicationRecord
  #アソシエーション
  belongs_to :user
  belongs_to :review

  validates_uniqueness_of :review_id, scope: :user_id
end
```

userは1つの投稿に対して１つしかいいねをつけられないようにするためにバリデーションを記述しました。

https://railsdoc.com/validation#validates_uniqueness_of

`validates_uniqueness_of`によって属性の値が一意であることをバリデーションが成立します。

```.rb
 validates :review_id, uniqueness: true
```

しかしこのような記述では1つの投稿に対して1つしかいいねが押せないことになってしまいます。

そのために`scope`を使って、範囲を指定して、一意かどうかを判断します。
週刊Transformer（画像認識向け）8号

凄まじい勢いで増殖中のTransformer論文＋αにとりあえず、目を通しつつコメントを残していく。内容があっている保証はない。

[FcaNet: Frequency Channel Attention Networks](https://arxiv.org/pdf/2012.11879.pdf)
SENetにDCT!

[Dataset Distillation with Infinitely Wide Convolutional Networks](https://arxiv.org/pdf/2107.13034.pdf)
Google論文。学習データを減らそうって方向。たったの10枚でCIFAR-10の64%精度が出るらしい！ 

[Refiner: Refining Self-attention for Vision Transformers](https://arxiv.org/pdf/2106.03714.pdf)
head変えて、Conv入れてSOTA。

---

[Contextual Transformer Networks for Visual Recognition](https://arxiv.org/pdf/2107.12292.pdf)
Attentionの構造をシンプルにした。

[Go Wider Instead of Deeper](https://arxiv.org/pdf/2107.11817.pdf)
ViTのFFNレイヤーを変更して、学習可能なパラメータ数を増やすことで、WideNetの学習を良くした。

[Multi-Stream Transformers](https://arxiv.org/pdf/2107.10342.pdf)
TransformerベースのEncorder-Decorderで、Encorderに分岐を入れると良い。

[An overview of mixing augmentation methods and augmentation strategies](https://arxiv.org/pdf/2107.09887.pdf)
data augmentationのSurvey

[CBNetV2: A Composite Backbone Network Architecture for Object Detection](https://arxiv.org/pdf/2107.00420v5.pdf)
Object detection向けのBackboneの形。細かいのとざっくりしたのを両方見られる。
[エラー]こんなミスは嫌だ

# はじめに
本記事では、これまでに学習した中で、
ヒューマンエラー、ケアレスミスをしてしまったことを紹介いたします。
私としても、同じことを繰り返さないために、備忘録としてここに記述します。

# ケアレスミス

###resources
例
（正）

```ruby
resources :prototypes
  resources :prototypes do
    resources :comments, only: :create
  end
resources :users, only: :show
```

（誤）

```ruby
resources :prototypes
  resources :prototypes do
    resources :comments, only: :create
resources :users, only: :show
end
```

usersまでネストしていたため、
Prefixも異なる事態に陥りました。

###モデル
(正)model
(誤)medel

見つけた時は、笑いが止まりませんでした。

###locals
以前の記事にも、載せましたが、
（誤）local
(正)locals

です。

###img src

(誤)img scr
(正)img src

###eachメソッド
例
（正）

```ruby
<% @prototype.comments.each do |comment| %>
```

(誤)

```ruby
<%= @prototype.comments.each do |comment| %>
```

=をつけるととんでもないぐらいブラウザに情報が飛び交う。
何に＝をつけるのか、つけないのか正確に理解する必要があります。

###終了タグの抜け
そのままの意味です。

###アソシエーション
(正)

```ruby
belongs_to :user
has_one_attached :image
has_many :comments , dependent: :destroy
```

(誤)

```ruby
belong_to :user
has_one_attached :image
has_many :comment , dependent: :destroy
```

「s」抜け。見つけることは困難を極めます。

###render
（正）

```ruby
 if prototype.save
     redirect_to prototype_path
 else
     render :edit
 end
```

（誤）

```ruby
 if prototype.save
     redirect_to prototype_path
 else
     render_to :edit
 end
```

redirect_toに引っ張られないように。

###７つのアクション
new・・・新規投稿ページを表示
create・・・データの投稿を行う

*逆にしない！！


# 終わり
キリがないので、
これで終わりにします。

とにかくミスが発覚した時は、
例えケアレスだからと言って軽く扱わず、
間違えたことをアウトプットし、なぜ間違えたのかフィードバックを行うよう心がけましょう。

引き続き頑張ります！！
Ruby HTTPClientでpostする

簡単なことなんだけどbodyを入れるのがうまくいかず詰まったのでメモ

```ruby
require 'httpclient'
require 'json'

client ||= ::HTTPClient.new

# body を jsonにする必要がある
body = JSON.generate({ hoge: { moge: 1234 } })
# railsの場合は to_json で ok

header = {
  'Content-Type' => 'application/json'
}

client.post "https://example.com/api/hoge/moge", body: body, header: header
```

---

※こちらの記事は自ブログからの転載です

https://akinov.hatenablog.com/entry/2021/07/30/212825
インスタンス時に指定の回転を加える方法

課題点「細い玉の形状でまっすぐ玉を飛ばしたい」
![スクリーンショット (33).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/788590/99dda567-a62e-af0b-5216-1545d65e07ea.png)

解決方法「オブジェクトを回転させよう」

1.どうやったらまっすぐになるか考えてみよう
「Rotation(0,0,0)だと変な向きになっちゃう」
![スクリーンショット (37).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/788590/4e9e20b0-ce09-c67e-1a06-db46ed8261d5.png)
「Rotation(90,0,0)だとうまくいった！」
![スクリーンショット (38).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/788590/116b6d80-d70e-ad87-7823-c04110c012ff.png)

自分が作った玉のオブジェクトの形によって、回転する軸や量が変わるのでまっすぐになる向きを考えてみよう。


2.プログラムを変更しよう

変更前

```ｃ＃:instance.cs
void Shoot()
	{
        GameObject clone=Instantiate(bulletObj,transform.position,Quaternion.identity);
        clone.GetComponent<Rigidbody>().AddForce(transform.forward* bulletSpeed);
    }
```

注目ポイント「Instantiateの()の中の意味」
()の中にいれるものは３つ
１つ目はクローンしたいゲームオブジェクト
２つ目はクローンしたゲームオブジェクトの座標
３つ目はクローンしたゲームオブジェクトの回転

なので下のプログラムの意味は
Instantiate(bulletObj,transform.position,Quaternion.identity);
クローンする(弾ゲームオブジェクト,このプログラムを持っているゲームオブジェクトの座標,Rotation(0,0,0));
*Quaternion.identity =  Rotation(0,0,0) =無回転状態
Rotation(0,0,0)だと変な向きになったので、Quaternion.identityを変えたい！
Rotation(0,0,0)をRotation(90,0,0)にすればまっすぐ弾が回転しそう...

変更後

```ｃ＃:instance.cs
void Shoot()
    {
        Quaternion rot =Quaternion.Euler(90,0,0);
        GameObject clone=Instantiate(bulletObj,transform.position,rot);
        clone.GetComponent<Rigidbody>().AddForce(transform.forward* bulletSpeed);
    }
```
Quaternion.Euler(90,0,0) =Rotation(90,0,0)にしてインスタンスをすると弾がまっすぐ飛びます
上の画像のようにRotation(90,0,0)で生成されて、弾が飛ぶようになりました！
macOS か Windows かハゲるほど悩んで macOS に落ち着いた話

# 機能面では Windows と macOS には本質的な差がない

Windows の暗黒時代からすれば、いまの Windows は相当進化していて、断然使いやすくなっていると思います。

UI・操作性が改善されてライトユーザに優しくなり、カスタマイズの自由度が高くなってミドルユーザへの訴求も強くなっています。

さらに、マイクロソフトが WSL の提供に力を入れ始めてからは、UNIX 系の環境を好むプロユーザ（ウェブアプリの開発者など）も Windows を使えるようになりました。少なくとも機能の面では、もはや Windows と macOS はほとんど変わらなくなっていると思います。

そうなると、世界の OS シェアの約９割を握る Windows の方が、いろいろと融通がきいて便利ではないか。使えるソフトウェアの数も違うし、情報の量も全然違う。近々には Windows 11 がリリースされることだし、いっそ macOS から Windows に回帰しようか……

そう考え始めていました（私はもともと Windows 派で、ウェブアプリ開発の会社に転職したことで macOS に乗り換えた人）

そこで、納戸に放置していた Windows マシンを引っ張り出してあれこれいじり回し、機能面で差がないことを検証し、一時は個人的に乗り換えの機運が高まっていたのですが……総合的に考えると macOS の方がポイントが高いという判断になりました。

# なにを検証したのか？

検証した項目と評価結果は、次のとおりです。
（少ないですが、もちろんすべて完全に「個人的な」ものですので注意）

|項目| macOS | Windows |備考|
|:-|:-:|:-:|:-|
|UNIX 系の環境が使える|○|◎|Windows は WSL で完璧に UNIX 系 OS を使える。macOS はやや特殊な面がある|
|Emacs が使える|◎|○|Mac だと専用ビルドがあるのでカスタム不要で完璧に動く|
|使えるソフトウェアの数|△|◎|動くソフトウェアの数はやはり Windows が圧倒的|
|インターフェースの美しさ| ○ | ○ |いずれも自分好みにカスタムできる余地が大きい|
|ブラウジングのストレスのなさ|◎|△|Windows には納得のいくジェスチャ機能がない|
|細かい部分での使い心地|◎|×|カーネルレベルでサポートする macOS が圧倒的|

要するに、下２つの項目（自分でも重要と気づいていなかった非本質的な機能）で macOS に軍配が上がりました。特に「使い心地」が Mac の方が遥かに上で、私は意外とそれを重視していたのでした。

# 「使い心地」とはなにか？

抽象的に説明すると「スイッ」というあの操作感覚です。例えば、macOS ではウィンドウをスクロールさせると、無段階で慣性がついてスルスルっと画面が動くわけですが、Windows ではそこまでのユーザエクスペリエンスは得られません。

この制御はデバイスドライバのレベルでは実現できず、カーネルレベルで実現するわけですが、macOS はこの細かなユーザエクスペリエンスを重視して作り込んでおり、それが圧倒的にすばらしい。これに慣れると、たまにガクガクする Windows にストレスを感じてしまいます。

これに関連して、どのブラウザを使っても、TrackPad を使ったブラウジングの快適性が全然違うことに気づきました。私は [BetterTouchTool を使った Magic Trackpad を使っている](https://qiita.com/hajime-f/items/3e3742e8db975c89b062)のですが、この操作性に慣れてしまってもう他のデバイスを使えません。

もちろん、Windows にもドライバがあるので使ってみたのですが、操作性がビミョーーに違う。この小さな差がブラウジングのストレスに直結し、その結果「ダメだ。。」となってしまいます。

# 要するに好みの問題

結局、本質的な機能に差がない以上、個人の好みに根ざした非本質的な違いしかないわけで、私の場合はそれが macOS に傾いたというだけでした。

もちろん、「自分にとって必須のソフトウェアが macOS で提供されていない」とか、「ゲームをバリバリ楽しみたい」とか、そういう事情があるなら Windows 一択でしょうし、「iPhone との連携の良さは外せない」とか、「iCloud にロックインされている」とかなら macOS 一択でしょう。

要するに、完全に好みと個人的な事情の問題です。
当たり前すぎる。

たまに、「絶対に Windows でしょ」とか「Mac 以外あり得ないっしょ」とか、どちらか一方をやたら推してくる人を見かけるのですが、自分のやりたいこと、好み、使用範囲などを総合的に考えて選べばいいんじゃないかな、と個人的に思うのでした。
（まあ、実際に両方使ってみないと分からないんですけどね）
pythonでsqliteを利用しようとしたら、AttributeError: 'builtin_function_or_method' object has no attribute 'execute'とエラーが出た。

# エラー発生時の状況
sqliteを利用して、入力した文字を検索する辞書アプリを作成していたところ、下記のエラーが発生した。

# エラー文
```
DEPRECATION WARNING: The system version of Tk is deprecated and may be removed in a future release. Please don't rely on it. Set TK_SILENCE_DEPRECATION=1 to suppress this warning.
Exception in Tkinter callback
Traceback (most recent call last):
  File "/Users/{user名}/.anyenv/envs/pyenv/versions/3.9.1/lib/python3.9/tkinter/__init__.py", line 1884, in __call__
    return self.func(*args)
  File "/Users/{user名}/Desktop/ejdict/jisyo.py", line 15, in search_dic
    rows = c.execute(sql, (word,))
AttributeError: 'builtin_function_or_method' object has no attribute 'execute'
```
# 解決方法
sqlite3に接続する際に、文法の誤りがあった。

```python
    # データベースへ接続する
    conn = sqlite3.connect("ejdict.sqlite3")
    c = conn.cursor # cursorの後の「()」が抜けている。
```

正しくはこう

```python
    # データベースへ接続する
    conn = sqlite3.connect("ejdict.sqlite3")
    c = conn.cursor()
```
[Rails]Capistranoで自動デプロイで気をつけたいこと

##はじめに
前回、Capistranoによる自動デプロイを導入しましたが、その中で個人的に、コマンド一つ覚えていればいいかと勝手思っていましたが、自動デプロイする前にやるべきことがあります。

それを簡単に記事に残しておきます。
よろしくお願いします。

##ローカルでVScodeを修正した場合
これは単純にアプリの改修や変更を行った場合、必ずリモートリポジトリにコミット、プッシュを行います。
もしブランチを切っている場合はmergeまで行います。

その後、一度プロセスをkillします。
例↓

まずはプロセスを確認します。

```terminal:ターミナル
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ ps aux | grep unicorn

ec2-user 17877  0.4 18.1 588472 182840 ?       Sl   01:55   0:02 unicorn_rails master -c config/unicorn.rb -E production -D
ec2-user 17881  0.0 17.3 589088 175164 ?       Sl   01:55   0:00 unicorn_rails worker[0] -c config/unicorn.rb -E production -D
ec2-user 17911  0.0  0.2 110532  2180 pts/0    S+   02:05   0:00 grep --color=auto unicorn
```

続いてプロセスをkill

```terminal:ターミナル
# 上記の例だと「17877」
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ kill プロセス番号
```

そして最後にローカルのアプリディレクトリで```bundle exec cap production deploy```を実行して完了。

##ローカルでデータベース関連の内容を修正した場合
もしデータベース関連の修正を行った場合、まず本番環境で下記の二つのコマンドを実行します。
*※実行する際、「DISABLE_DATABASE_ENVIRONMENT_CHECK=1」というオプションが必要です。*

```terminal:ターミナル(本番環境)
rails db:drop RAILS_ENV=production

rails db:create RAILS_ENV=production
```

その後、一度プロセスをkillします。
例↓

まずはプロセスを確認します。

```terminal:ターミナル
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ ps aux | grep unicorn

ec2-user 17877  0.4 18.1 588472 182840 ?       Sl   01:55   0:02 unicorn_rails master -c config/unicorn.rb -E production -D
ec2-user 17881  0.0 17.3 589088 175164 ?       Sl   01:55   0:00 unicorn_rails worker[0] -c config/unicorn.rb -E production -D
ec2-user 17911  0.0  0.2 110532  2180 pts/0    S+   02:05   0:00 grep --color=auto unicorn
```

続いてプロセスをkill

```terminal:ターミナル
# 上記の例だと「17877」
[ec2-user@ip-172-31-23-189 <リポジトリ名>]$ kill プロセス番号
```

そして最後にローカルのアプリディレクトリで```bundle exec cap production deploy```を実行して完了。

##Nginxを修正した場合
Nginxの修正を行った場合は下記コマンドを実行します。

```terminal:ターミナル
sudo systemctl restart nginx
```

##最後に
Capistrano導入後、bundle exec cap production deployのコマンドさえ打てば自動デプロイしてくれると思っていましたが、もう一手間加えないといけなくて、私は少し失敗しました。
このような細かいところもしっかり身につけたいと感じました。
embind で C++ クラスの WASM バインディングを書くメモ

embind = pybind11 の WASM 版みたいな感じです.

https://qiita.com/chikoski/items/462b34db61daf13a7897

ありがとうございます.

## 注意点

pybind11 と同じく, ドキュメントはあまり揃っていません...
なのであまり複雑なシグネチャのバインディングを書こうとするとハマりそうです.

C++ API そのままを頑張って expose するのではなく, wasm 用(JavaScript インターフェイス用)に API を整理してあげるとよいでしょう.


## struct

`struct` を struct のように扱うのはできないようです.

```
struct Point2f {
  float x;
  float y;
};
```

を, `value_array` or `value_object` でバインドだと, JavaScript での配列 or object として扱わないといけません(型付オブジェクトみたいのは作れない)

```
var p = new Module.Point2f(); // NG
console.log(p.x);
```

struct にコンストラクタを書かずにやるには, 

```
Point2f make_point(float x, float y);
```

みたいに struct を返す関数を作るしかなさそうです. 

JavaScript の流儀に合わせるのであれば, struct も class としてバインディングしてあげるのがよさそうです.

## std::vector, std::map

`std::vector`, `std::map` は標準では対応していないですが, 定義のためのヘルパー関数があります.

https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html#built-in-type-conversions


```
emscripten::register_vector<int>("vector<int>");
```
OpenCV・PIL・PyTorchの画像要素の順番と3次元配列のイメージの違い

結論から言うと、画像要素はそれぞれこのような順番の違いがある

- **OpenCV： [高さ、幅、色チャネル]**
- **PIL： [高さ、幅、色チャネル]**
- **PyTorch： [色チャネル、高さ、幅]**


故に、PyTorchでは必ず

```
img_transformed = img_transformed.numpy().transpose((1, 2, 0))
```
のように要素を入れ替える必要があるので注意


## 通常のnumpy3次元配列とOpenCVやPILの3次元配列のイメージの違い

通常のnumpy3次元配列はこのようなイメージだと思う


### 通常のnumpy3次元配列

```python
	X = np.array([[[1,  2,  3], 
    		       [4,  5,  6]],
    			  [[7,  8,  9],
				   [10, 11, 12]],
				  [[13, 14, 15]],
				   [16, 17, 18]]])
```

![c88368bf85397bac11c032e533726c3b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191313/be011ec4-02b9-fb84-0061-4d9154dec217.png)

```python:要素の取り出し
 # 最初の数字が三次元目の軸（奥行き方向）、2番目が二次元目の軸（縦）、3番目が一次元目（横）
 >>> X[0, 1, 2]
 6

 # 奥行き軸(axis=0)の0番目を取り出す
 >>> X[0, :, :]
 array([[1, 2, 3],
        [4, 5, 6]])
 
 # 縦軸(axis=1)の1番目を取り出す
 >>> X[:, 1, :]
 array([[ 4,  5,  6],
        [10, 11, 12]])
 
 # 横軸(axis=2)の２番目を取り出す
 >>> X[:, :, 2]
 array([[ 3,  6],
        [ 9, 12]])
``` 

![9048611b0d6f4f4f3a97948fc4be7ac3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191313/1ab6a9ad-067c-cae4-9e64-29eda6b09cc1.png)

**[奥行き=RGBチャネル, 高さ, 幅] の順なのでOpenCVやPILで読み込んだ画像をPyTorchに変換するとこのイメージと同じになる**

しかしその前に一般的に画像処理に使われるライブラリOpenCV, PILでは同じ3次元ではあるのだが、配列構成のイメージが違う

### OpenCV, PILの3次元配列
 OpenCVやPILなどは、 [高さ, 幅、奥行き=RGBチャネル] の順になる（OpenCVはBGRの順なので注意）

```python
 import cv2
 img = cv2.imread('img.png')
 print(img.shape)
 > (172, 180, 3)
 
 print(img)
 >
 [[[ 58  35  33]
   [ 57  33  30]
   [ 54  29  25]
   ...
   [  7   6   8]
   [  8   8   9]
   [ 10  10  11]]
 
  [[ 60  36  34]
   [ 60  34  31]
   [ 56  30  26]
   ...
   [  6   6   8]
   [  8   7   9]
   [ 10   9  10]]
 
  [[ 61  37  34]
   [ 62  36  32]
   [ 60  33  29]
   ...
   [  6   5   7]
   [  7   7   8]
   [  9   9  10]]
```

<img width="500" alt="OpenCV配列イメージ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191313/6c21e380-fb1a-4165-3391-5d900164b0c4.png">

```python:要素の取り出し
 # 行（高さ）を取得
 print(img[0, :, :].shape)
 print(img[0, :, :])
 >
 (180, 3)
 [[58 35 33]
  [57 33 30]
  [54 29 25]
  ...
  [ 8  8  9]
  [10 10 11]]
  
  
  # 列（幅）を取得
  print(img[:, 0, :].shape)
  print(img[:, 0, :])
  >
  (172, 3)
  [[ 58  35  33]
   [ 60  36  34]
   [ 61  37  34]
   [ 62  36  34]
   ...
   [139  89  69]
   [121  72  53]]
   
   
   # 奥行き（チャネル）を取得
   print(img[:, :, 0].shape)
   print(img[:, :, 0])
   >
   (172, 180)
   [[ 58  57  54 ...   7   8  10]
    [ 60  60  56 ...   6   8  10]
    [ 61  62  60 ...   6   7   9]
    ...
    [157 154 144 ...  20  23  24]
    [139 134 124 ...  22  24  25]
    [121 116 107 ...  22  23  25]]
```

**[高さ, 幅, 奥行き=RGBチャンル] の順なので次元ごとの要素の取り出し方が通常のnumpy及びPyTorchとは異なることに注意**


高さと幅のイメージが直感的に異なるが実態はこうなっている。
なぜこうなっているかだが、テレビのディスプレイなどでは、1画素の中でRGBの光の混色で色を表す仕組みであるため配列の横軸方向に色チャネルを並べ、次点で高さ、幅という順番の３次元配列になったのだと思われる。

補足：
※ 操作時には、最も外側の次元から順に取り出していくと覚えると良い。

#### 参考
https://qiita.com/ken_yoshi/items/4cbe3abb7d46c5252fdd
Wio LTE for Arduino で SD カードを使う

 次のページを参考にしました。
[SDReadWrite.ino](https://github.com/SeeedJP/WioLTEforArduino/blob/master/examples/basic/SDReadWrite/SDReadWrite.ino)

ファイルが存在する時に、そのファイルを削除するようにしました。削除しないと、ファイルの末尾に Append されます。

```text:sd_test/sd_test.ino
// ---------------------------------------------------------------
/*
	sd_test.ino

					Jul/30/2021
*/
// ---------------------------------------------------------------
#include <SDforWioLTE.h>

#define FILE_NAME "test_cc.txt"

// ---------------------------------------------------------------
void setup()
{
	delay(1000);
	SerialUSB.println("*** sd_test *** setup *** aaa ***");
	delay(1000);
	SerialUSB.println("*** sd_test *** setup *** bbb ***");
	delay(1000);
	SerialUSB.println("*** sd_test *** setup *** ccc ***");

	SerialUSB.println("");
	SerialUSB.println("*** START ***");

	SerialUSB.println("### Initialize SD card.");
	if (!SD.begin()) {
		SerialUSB.println("### ERROR! SD.begin ###");
		}
	else
		{
	file_write_proc();
	file_read_proc();
		}

	SerialUSB.println("*** Setup completed ***");
}

// ---------------------------------------------------------------
void loop()
{
	SerialUSB.println("*** loop *** aaa ***");
	delay(3000);
	SerialUSB.println("*** loop *** bbb ***");
	delay(3000);
}

// ---------------------------------------------------------------
void file_write_proc()
{
	File myFile_out;
  
	SerialUSB.println("### Writing to "FILE_NAME".");

	if (SD.exists(FILE_NAME))
		{
		SD.remove(FILE_NAME);
		}

	myFile_out = SD.open(FILE_NAME, FILE_WRITE);
	if (!myFile_out)
		{
		SerialUSB.println("### ERROR! SD.open ###");
		}
	else
		{
		myFile_out.println("testing 1, 2, 3, 4, 5.");
		myFile_out.println("Good Morning.");
		myFile_out.println("Good Afternoon.");
		myFile_out.println("Good Night.");
		myFile_out.println("Jul/30/2021 PM 20:00");
		myFile_out.close();
		}
}

// ---------------------------------------------------------------
void file_read_proc()
{
	File myFile_in;

	SerialUSB.println("### Reading from "FILE_NAME".");
	myFile_in = SD.open(FILE_NAME);
	if (!myFile_in) {
		SerialUSB.println("### ERROR! SD.open ###");
	}
	else
		{
		SerialUSB.println(FILE_NAME":");
		while (myFile_in.available()) {
			SerialUSB.write(myFile_in.read());
			}
		myFile_in.close();
		}
}

// ---------------------------------------------------------------
```

実行結果
![sd_test_jul30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/28bf6f94-9d2b-f7d4-5411-8daf48584b5e.png)
Vue CLI で yup を IE11 でも動くようにビルドする

# バージョン

- @vue/cli-service: 4.5.0
- yup: 0.32.9

# 問題

yup 0.32 系はアロー関数が使われており、そのままでは IE11 では動きません。
下記のコメントの通り、自分たちのビルドプロセス上で yup をビルドする必要があります。

https://github.com/jquense/yup/issues/1175#issuecomment-811480581

> For folks that continue to need IE 11 support, you have my sympathies! You can continue to use yup by compiling it down further as part of your build process. Tools like create-react-app will do this automatically.

# 設定

`vue.config.js` に `transpileDependencies` の設定を追加しビルド対象に追加できます。

https://cli.vuejs.org/config/#transpiledependencies

```js
module.exports = {
  transpileDependencies: ["yup"],
}
```
拡張機能でContent-Security-Policyを回避したい (VivaldiでGoogle翻訳を使いたい)

## 動機

- vivaldi搭載の翻訳では精度が良くないのでGoogle翻訳を使いたい
- ページにGoogle翻訳スクリプトを埋め込む方式の拡張機能だとGithubなどのページではContent-Security-Policy(CSP)が設定されておりそのスクリプトが実行できない
- CSPはHTTPヘッダで制御されているのでヘッダを書き換えればCSPは無効化できる
- ヘッダの書き換えは拡張機能で行える

## 方法
- 今回、ヘッダの書き換えは既存の翻訳拡張機能を改造することで行う
- 改造したい拡張機能のフォルダを「パッケージ化されていない拡張機能を読み込む」で読み込む
- 下記のように `manifest.json` の `background` に `scripts` として `background.js` を指定する `permissions` に `webRequest` , `webRequestBlocking` を追加する

```jsonc:manifest.json
{
// ...
   "background": {
      "scripts": ["background.js"]
   },
// ...
   "permissions": [ "tabs", "http://*/", "https://*/", "contextMenus", "webRequest", "webRequestBlocking" ],
// ...
}
```

- `background.js` にヘッダを削除する js を追記する

```javascript:background.js
// ...
chrome.webRequest.onHeadersReceived.addListener(function(detail){
	const headers = detail.responseHeaders.filter(e => e.name !== "content-security-policy")
	return {responseHeaders: headers}
}, {urls: ["<all_urls>"]}, ["blocking", "responseHeaders"])
```
- このjsでヘッダ内のcontent-security-policyを消して読み込むことができる
- 2つ目の引数のオブジェクトのプロパティ `urls` には `<all_urls>` で全てのページが対象になる
- これを行うことでXSSなどの攻撃に対するセキュリティレベルが低下するので注意(`urls`で都度指定するのが良い)

## 参考ページ
[Chrome 拡張機能で CSP を無視させる](http://var.blog.jp/archives/74730794.html)
COCOフォーマットのアノテーション領域をさくっと拡大縮小する

# はじめに
COCOフォーマットのアノテーション領域(segmentation)の領域を拡大する必要があり、[Clipper](http://www.angusj.com/delphi/clipper.php)を使用すると簡単にできたのでシェアします(RLEは非対応)。コードでは、ClipperのPythonバインディング (pyclipper)を使用しています。

# インストール
```bash
pip3 install pyclipper
```

# 実装
PyclipperOffsetクラスのAddPath()メソッドを使用します。オフセットの仕方には3種類ありますが、今回はラウンド形状でパスを変形させています。使い方の詳細はClipperのサイトをご参照ください。areaとbboxはData Loader等で自動計算される想定です。

```python:coco_inflator.py
import argparse
import itertools
import json
import pyclipper

def inflate_segmentation(seg, width):
    it = iter(seg)
    polygon = tuple(zip(it, it))
    pco = pyclipper.PyclipperOffset()
    pco.AddPath(polygon, pyclipper.JT_ROUND, pyclipper.ET_CLOSEDPOLYGON)
    solution = pco.Execute(width)
    return list(itertools.chain.from_iterable(solution[0]))

def main():
    parser = argparse.ArgumentParser(description='COCO segmentation inflator tool.')
    parser.add_argument('input', help='json format')
    parser.add_argument('output', help='jon format')
    parser.add_argument('-o', '--offset', type=float, default=10.0, help='inflation offset')
    args = parser.parse_args()

    with open(args.input) as fin:
        json_in = json.load(fin)

        for ann in json_in['annotations']:
            ann['segmentation'] = [ inflate_segmentation(seg, args.offset) for seg in ann['segmentation'] ]
            ann['area'] = ""
            ann['bbox'] = ""

        with open(args.output, 'w') as fout:
            json.dump(json_in, fout, indent=4)

if __name__ == '__main__':
    main()
```

# 実行例
```bash
python3 coco_inflator.py --offset 10 input.json output.json
```

下記は、segmentationデータを図示したものです(黒は、元のsegmentation、青と緑は拡張後のsegmentation)。
![output.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109483/be4857ea-ddf9-74b2-3a1c-3ba586f1da9f.png) 
出典：[SDNET2018 7069-101.jpg](https://www.kaggle.com/aniruddhsharma/structural-defects-network-concrete-crack-images)
右クリックからWinPythonのCommand Promptを開けるようにする方法

# 記事の目的
エクスプローラ上での右クリックからPython環境にパスが通ったコマンドプロンプトを開けるようにする方法を説明します、めちゃ便利です！

![Animation_20210809_1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561868/eb4e0c32-c023-90b5-231b-85d18942352c.gif)

# 前提条件
## 導入環境
導入先PCの想定環境を整理する。
- OSはWindows10であること
- WinPythonがインストールされていること
　(WinPythonについては後述する。なお筆者はWPy64-3860をインストールした)
- PCに管理者権限が付与されていること(サラリーマンの方は気にするところのはず)

## WinPythonとは
WinPythonは、Windows系に特化した科学技術系Pythonディストリビューションの一つである。同種でもっとも有名なディストリビューションではAnacondaが存在するが、2020年頃から大企業に対しては商用利用を有料化する方針となった。WinPythonはオープンソースで商用利用可能であるため、Anacondaからの移行先として最も有力な開発環境である（と筆者は思っている）。

導入は以下の公式サイトから Winpython64-X.X.X.X.exe(Xはバージョン)をダウンロードして
好みの場所(例えばC直下)などでダブルクリックして展開すればとりあえずOK。(詳細はまた別の記事にします)

https://winpython.github.io/

## WinPythonのコマンドプロンプトの従来の使い方
WinPythonのコマンドプロンプトとは、Python関係へのパスがロード済みのコマンドプロンプトを指す。たとえば「WinPython Command Prompt.exe」を実行することで開く。ここから、例えば「ipython」などのPythonコマンドが実行可能である。
自分の作業したいディレクトリに移動するには、ここから「cd XXXX」(XXXXは移動先のパス)などを実行する必要があった。これが地味にひと手間。

![fig1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561868/210fa04e-595c-f400-18f4-8a75c478a283.png)


# 【本題】右クリックにWinPythonコマンドプロンプトを追加する
## 実施前の注意
レジストリを修正することになるので操作は慎重に行うこと。

## 設定方法

レジストリエディタを開く。
![fig2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561868/e1334746-16d9-9893-0992-60cc3d723e09.png)

「コンピューター\HKEY_CLASSES_ROOT\Directory\Background\shell」の中に、新しいキーを追加して（「shell」を右クリックから）、名前を「winpythonPrompt」などに変更する。

![fig3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561868/74fab6b7-10cf-5ef4-5e02-c0235a5aca41.png)

左窓のいま作った「winpythonPrompt」を選択して右窓の「(限定)」値をダブルクリックして、値を「WinpythonPromptをここで開く」などとする。

![fig4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561868/ce204603-79a5-5477-57c7-dbd0f49d67c3.png)

左窓の「winpythonPrompt」を右クリックしてさらにキーを追加し、名前を「command」とする。
左窓のいま作った「command」を選択して右窓の「(限定)」値をダブルクリックして、値を「cmd.exe /K C:\WPy64-3860\scripts\env_for_icons.bat」とする。(WinPythonをC直下にインストールしていない場合は、env_for_icons.batの絶対パスを見直すこと。)

(P.S.(2022.06.12) Winpythonの後継のバージョンだと「コマンドの構文が誤っています。」の
　エラーが出る(が一応使えはする)ようになった。いろいろ試した結果、
　「env_for_icons.bat」ではなく「env.bat」が望ましいようだ）

![fig5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561868/729ed5fc-8038-6f33-b120-616ee03c30ea.png)

## 設定結果の確認
エクスプローラ上で右クリックして、「WinpythonPromptをここで開く」が表示されることを確認し、これを選択すれば、エクスプローラ上のパスでコマンドプロンプトが開き、Python環境がロードされていることが確認できる。あら便利！！

![fig6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561868/178b1a6b-bbbf-fde6-3add-3228f9e9dea0.png)

![fig7.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561868/7407742d-0513-3d05-7d6e-9186ad26ea6c.png)

## ポイントのおさらい
今回の設定のポイントは以下の２つであった。
- WinPython環境をロードするためには、env_for_icons.batを実行してやればよいということ
（Anacondaの場合は「activate.bat」がこれにあたる）
- レジストリを弄れば右クリックにアプリケーションの実行コマンドを登録できるということ

(P.S. (2022.06.12) Winpythonの後継のバージョンだと「コマンドの構文が誤っています。」の
　エラーが出る(が一応使えはする)ようになった。いろいろ試した結果、
　「env_for_icons.bat」ではなく「env.bat」が望ましいようだ）

## 参考にした情報
https://gist.github.com/jiewpeng/8ba446acf329b1801bf91db767d179ea

# 最後に(筆者について)
私事だが、今回記事が筆者のQiita初投稿である。筆者は宇宙関連製品の開発に従事する、いわゆる「ものづくりエンジニア」である。これから、特にものづくりの開発現場で活用できるようなちょっとしたTipsを発信していきたい。
M1 mac docker error: exec user process caused "exec format error"

M1 mac でdockerのイメージをビルドし、GKEで利用しようとした所、エラーが発生したので解決方法を書いておく。

# エラー内容
GCP側で発生したエラーは以下である。

```
standard_init_linux.go:211: exec user process caused "exec format error"
```

# 原因
このエラーは、dockerfileをビルドした M1 mac とコンテナを実行するマシンのCPUアーキテクチャが異なるために発生する。

# 解決策
amd64のCPUで実行できるようにdocker buildにオプションを指定する。
Dockerfileが存在するディレクトリで以下のコマンドを実行する。

```
docker build --platform amd64 -t NAME(ここには好きな名前をつける) .
```


# 参考記事
[ECSのタスク起動時に「standard_init_linux.go」関連のエラーが出た場合の対処方法](https://dev.classmethod.jp/articles/how-to-fix-standard-init-linux-error/)
[docker, apple m1, nginx and standard_init_linux.go:211: exec user process caused "exec format error"
](https://axcoto.com/notes/2021-03-13-docker-apple-m-nginx-and-standard-init-linux-go-exec-user-process-caused-exec-format-error-/)
AIサーバーはどこから情報をもらうべきか

# 前提
AIサーバーをここでは、機械学習・ディープラーニングを実行するPythonのサーバーだと仮定しています
Pythonサーバーには、結果を返すためのAPIが生えていて、学習を定期実行しているサーバーです。

AI学習を行うため、サービスをまたいでデータ量が必要になります。
私が実際に作る時に検討して、採用したものと不採用にしたものを紹介していきます。

# 各サービスからAPI経由で受け取る(不採用)
## メリット
- サービスを疎結合に実装ができる
- マイクロサービスアーキテクチャの概念に則っている

## デメリット
- 必要なデータ量が多いのでサーバーに負荷をかけてしまう
- 取得に時間がかかる

# DWH(BigQuery)に直接つなぐ
## メリット
- DB接続のため、取得が比較的早い
- S3の情報などもBigQueryにアップロードすることができるので、楽

## デメリット
- DWH側の設計変更をもろに受ける

# S3に前処理したデータをアップロードしてもらう(採用)
##　メリット
- アップロードで負荷をかけることがない
- BigQueryで中身を見やすい
- AWS Recommendation APIがこの方式を採用している

## デメリット
- データの型がつけづらい
- 若干データの自由度が高い
天才ではない私たちがコードを書く上でやってはいけない過ち



# 始めに
私たちは極めて優秀なエンジニアかもしれない。
社内であなたは頼りにされているかもしれないし、有名なOSSのコミッターかもしれない。
もしくは勉強会において多少有名な存在として認知されているかもしれない。
だが私たちは普通の人間だ。
コードを書くのは時間がかかることもあるし、丸一日もしくはそれ以上問題解決がまったく進まないこともある。
学び続けなければすぐに置いていかれるし、知らないことも多すぎる。

私たちは天才ではない。
完成されたコードが頭の中にあってそれをコード上に書き写すなんてことはできないし、
驚異的な集中力を持ち合わせているわけでもない。
OSSなど既存のものをより良いものに書き直して使うことはできない。

天才の話を聞きたい方はこの動画を見てみるといい

https://www.youtube.com/watch?v=HgYSjZaPcy4

今回の記事では、そんな天才ではない方がやってはいけないことをいくつか紹介していきたい
今回は自社開発の企業でチーム開発を行なっているエンジニアを対象としている

# コードを読めば大体わかるからコミュニケーションを取らない
一定以上の規模のコードは読んでもわからないものもあるし、
チームはあなたがすべてを読み終えるのを待ってはくれない

## 改善
コードを読むこと自体は非常に重要。
どうしてもわからないことや、自社特有のことはそこの担当の人などに聞いてみよう

# 1日以上かかりそうなタスクの分解をしない
1日以上かかりそうなタスクはゴールが明確に見えていることは少ない。
重要な機能の実装漏れが発生するし、いつ終わるのか見積もることができない

## 改善
時間がかかりそうなタスクは2、3時間で終わる単位に分割しよう
(例)　TODOリスト一覧ページを実装する

[ ] (フロントエンド) TODOコンポーネントの実装 30m
[ ] (フロントエンド) ページ実装 1.5h
[ ] (サーバーサイド)　TODOテーブルの設計　30m
[ ] （サーバーサイド） TODOドメインモデル・リポジトリー層の実装 30m
[ ] （サーバーサイド） TODOアプリケーション層の実装 (APIエンドポイント実装・serviceクラスなどの実装) 1h

# 技術調査をするときに、メモを取らない
私たちの脳内のメモリはかなり小さい
その調査が長時間に渡るものであれば、気がついたら同じことを何度も調べているだろう

## 改善
外部ストレージに頼ろう
調べながらメモをする。調べる際に参考にしたサイトのURLをメモしておくと、時間を溶かすことなく調査が進むだろう

# 他人と比較する
「あの人はGolangを使って開発をできる。」
「REST API以外にもGraphQLや、Grpcをつかって開発ができる。」
「フロントエンドなのにサーバーサイドにも詳しい」
自分の知らないこと・できないことができる人を見て焦ってやるべきことを見失う、寄り道してしまう

## 改善
そもそも近年のプログラミングはかなり多岐に渡るのでわからないことは無限にある。
比較をすること自体がナンセンスだ
ある程度のレベルまでいくと比較はあまり意味をなさない。
Golangが得意なエンジニアとPythonが得意なエンジニアを比べるのは、悟空とルフィーどっちが強いか比べるようなものだ。
自分がやるべきこと、やりたいことだけに目を向けて昨日の自分を超えていこう

# NetFlixを見ながら仕事する
絶対にやめましょう。

## 改善
NetFlixを解約する

# 複数の機能開発を同時に行う
切り替える度に、現状がどうなっているかの把握で時間をロスします。

## 改善
コードを書く際は一定の時間を確保しましょう

▼複業でスキルを活かしてみませんか？複業クラウドの登録はこちら！
https://talent.aw-anotherworks.com/?login_type=none
HomebrewでVirtualBoxをアップデートすると、Docker Machine起動時にエラーになる

## 環境

macOS Big Sur

## 現象

Docker Machineで仮想マシン起動中に、
HomebrewでVirtualBoxのアップデートプロセスが走ると、
古いVirtualBoxのアンインストールプロセスで異常停止し、VirtualBoxの再インストールが必要になるのによく引っかかるので、
今回はちゃんと、Docker Machineの仮想マシンを停止してから、アップデートを実行したのだが下記エラーが発生し、
再インストールしても解消しない。

```shell
docker-machine start xxx
Starting "backend"...
(backend) Check network to re-create if needed...
(backend) Creating a new host-only adapter produced an error: /usr/local/bin/VBoxManage hostonlyif create failed:
(backend) 0%...
(backend) Progress state: NS_ERROR_FAILURE
(backend) VBoxManage: error: Failed to create the host-only adapter
(backend) VBoxManage: error: VBoxNetAdpCtl: Error while adding new interface: failed to open /dev/vboxnetctl: No such file or directory
(backend) VBoxManage: error: Details: code NS_ERROR_FAILURE (0x80004005), component HostNetworkInterfaceWrap, interface IHostNetworkInterface
(backend) VBoxManage: error: Context: "RTEXITCODE handleCreate(HandlerArg *)" at line 95 of file VBoxManageHostonly.cpp
(backend)
(backend) This is a known VirtualBox bug. Let's try to recover anyway...
Error setting up host only network on machine start: The host-only adapter we just created is not visible. This is a well known VirtualBox bug. You might want to uninstall it and reinstall at least version 5.0.12 that is is supposed to fix this issue
```

## 原因

MacのセキュリティであるGatekeeperが動いていただけだった。
HomebrewでVirtualBoxをアップデートすると、アンインストールを実行してから再インストールしているためだと思う。
https://github.com/Homebrew/homebrew-cask/blob/88c06c1853001ad921010e2eef7cd36abfed18ee/Casks/virtualbox.rb

## 対応

Macのsecurity & privacyからSystem software from developer “Oracle America, Inc.” was blocked from loading.を選び、Allowボタンを押す。

![Screen Shot 2021-07-30 at 19.18.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/25578/7d814131-3915-0541-3b35-f33d737c5066.png)

## 雑文

PCを新しくしてからmacOSの挙動が色々と変わっていて微妙に混乱する。
iOSエンジニアだった時はXcodeの関係などで最新のOSなど追っていたものだが、
バックエンドエンジニアになってからは、そこまでアップデートする必要性が出てないからな。。
色々なロードマップを書いてみた

#プログラミングを独学で学んで稼げるようになるまで

https://careerhub.jp/programming_roadmap20201019/

#Java
https://careerhub.jp/java-roadmap/

#Python
https://careerhub.jp/python-roadmap/

#動画編集
https://careerhub.jp/movie-edit-roadmap/
【PHP】array_key_existsの使い方

array_key_exists(イグジストス)とは、配列内の指定したキーが存在するかチェックする関数

※多次元配列で使用することはほぼない


```PHP
<?php
$rows = [
    10 => 'PHP',
    12 => 'Java',
    23 => 'JavaScript',
    33 => 'Ruby'
];

$start = hrtime(true); // 計測開始時間

if ( array_key_exists('23', $rows) ) {
    echo "配列内にMikeというキーは存在します\n";
}

$end = hrtime(true); 
echo '処理時間:'.($end - $start).'ナノ秒';
?>
```


```PHP
<?php

$rows = [
    10 => 'PHP',
    12 => 'Java',
    23 => 'JavaScript',
    33 => 'Ruby'
];

$start = hrtime(true); // 計測開始時間

foreach ($rows as $key => $row) {

    if(23 === $key){
        echo "配列内にMikeというキーは存在します\n";
        break;
    }
}

$end = hrtime(true); 
echo '処理時間:'.($end - $start).'ナノ秒';

?>
```
Vue3のv-forのref配列について

Vue3の公式サイトではv-forのref配列をこう書いています。

```sample.vue
<template>
  <p v-for=“item in items” :ref=“setItemRef”>{{item.text}}</p>
</template>

<script text=“javascript”>
export default {
  data() {
    return {
      items: [
        {text: “hoge”},
        {text: “huga”}
      ],
      itemRefs: []
    }
  },
  methods: {
    setItemRef(el) {
      if (el) {
        this.itemRefs.push(el)
      }
    }
  },
}
</script>
```

しかし、これだとDOMが更新されるたびにitemRefsに参照が追加されていってしまい、itemRefsの中に同じものが沢山ある状態になってしまいます。

なので、こっちの方がいいと思います。

```sample.js
setItemRef(el){
  if(el && !this.itemRefs.includes(el)){
    this.itemRefs.push(el);
  }
}
```
AngularでSCSSをCSSに変換する方法

SCSSの方がもっと効率いいとは思いますが、プロジェクトによってはSCSSよりCSSを希望する場合もあるので、すでにSCSSで作ったプロジェクトを途中でCSSに変換した時やったことをまとめて置きます。

## 目標
進行中のAngularプロジェクトをSCSSからCSSに変換
> ng g c compoment で新規コンポーネント追加時も、scssではなくcssにする

## 実施した環境：
Angular 12.0.0 
> 実際やってみたら、別にバージョンは気にしなくていいかなと感じました。おそらく今後のバージョンでも通用するかと思います。

## 修正した箇所

### src/angular.json 

> 「scss」で検索し、全てを「css」に変更

### src/style.scss 

> このファイルを src/style.css に変更

### 各コンポーネントで

*.component.scss ファイル名を *.component.css に変更

*.component.ts でstyleUrls: ['./*.component.scss'] のscssをcssに変更

以上でした。

### エラーが発生した場合

SCSSをCSSに変えると、一部CSSにない文法がエラーになります。それを一々CSSフォーマットに変える必要があります。

## 検証方法

上記の修正で全部正しく変更できたのかを確認するには、

```ng serve``` 

でcss関連のエラーが出るか確認が必要になります。

そして

```ng g c csstest``` 

みたいなコマンドでコンポーネントを追加し、追加されたスタイルファイルがcss拡張子になっているか確認できればOKです。

## 逆にCSSからSCSSにするには

同じやり方でいけると思います、ただし、SCSSの文法はCSSを兼しているので、CSS文法の直しはいらないと思います。

少しでもご参考になったらと思います。
Ruby(Rails)でどうやってSQLを作成するの？

ActiveRecordと呼ばれるものでSQLを発行しています。


「RubyとSQLの翻訳機」みたいなもの
Railsでモデルを定義するだけで簡単にSQLを発行することができる
※モデル：データベースにアクセスする為に準備するためのクラス


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/943494/29d09cbf-8170-b9e8-6efe-2541fb6330d1.png)

## ActiveRecord色々

### 作成
 User.create(name: "小田", email: "oda@gmail.co.jp")

```sql
INSERT INTO
  `users` (`name`, `email`, `created_at`, `updated_at`)
VALUES
  (
    '小田',
    'oda@example.org',
    '2021-07-30 09:18:57',
    '2021-07-30 09:18:57'
  )
```


### 検索
User.all

```sql
SELECT `users`.* FROM `users`
```

User.first

```sql
SELECT  `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
```

User.find(1)

```sql
SELECT  `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
```

User.where(title: '小田')

```sql
SELECT  `users`.* FROM `users` WHERE `users`.`title` = '小田' LIMIT 1
```

めちゃくちゃ便利

### 内部結合

■joins
User.joins(:user_work_experiences).where(user_work_experience: { id: 1 })

```sql
SELECT
  `users`.*
FROM
  `users`
  INNER JOIN `user_work_experiences` ON `user_work_experiences`.`user_id` = `users`.`id`
WHERE
  `user_work_experience`.`id` = 1
```

### 外部結合

■eager_load
User.eager_load(:user_work_experiences)

```sql
SELECT
  `users`.*,
  `user_work_experiences`.*,
FROM
  `users`
  LEFT OUTER JOIN `user_work_experiences` ON `user_work_experiences`.`user_id` = `users`.`id`
```

eager_loadは結合先のテーブルの情報も取得できるが、joinsはできない

joinsだとuser_work_experiences.job_idは取得できない。

```sql
NG
User.joins(:user_work_experiences).where(user_work_experience: { id: 1 }).job_id

OK
User.eager_load(:user_work_experiences).where(user_work_experience: { id: 1 }).job_id
```
### その他
preload
User.preload(:user_work_experiences)

```sql
SELECT  `users`.* FROM `users`;

SELECT
  `user_work_experiences`.*
FROM
  `user_work_experiences`
WHERE
  `user_work_experiences`.`user_id` IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
```


	
### eager_loadとpreload使い分け
データ量が膨大な場合だと、preload、eager_loadは、いずれにせよ多くのメモリを必要とする。
なので、アソシエーションの種類によって使い分けるべき。

#### 1対1あるいは1対Nのアソシエーションの場合はeager_load
データ量が増えても、1回のSQLでまとめて取得した方が効率的な場合が多いと思うので、eager_loadを良き。


#### N対Nのアソシエーションの場合はpreload
eager_loadよりも、preloadの方がSQLを分割して取得するため、レスポンスタイムは早くなるので、preloadが良き。


### デメリット
ActiveRecordに頼りすぎるとSQL自体の理解がおろそかになるから注意