OmniAICreator/Qiita-1.07M huggingface dataset:
Vuexで別のモジュールを呼び出す

## storeのactionから他のモジュールを呼び出したい

storeの更新をする際、別のモジュールも一緒に更新しようとしたのですが、
うまく出来ず時間を食ったので備忘録。

### データを取得するとき

```vue.js
export const actions = {
    getFunction ({ state, rootGetters }, payload) {
        // このモジュール内のデータを取得
        const localData = state.dataList

        // 別のモジュールからデータを取得
        const adminData = rootGetters["modules/admin/dataList"]
    }
}

```

### 他のモジュールにdipatchするとき

```vue.js
export const actions = {
    saveFunction ({ dispatch }, payload) {
        dispatch('modules/admin/dataList', payload, { root: true })
    }
}
```

このとき、`dispatch`の第３引数に`{ route: true }`をつけてあげれば良い。
ないとダメで、これでハマりました。
【Ruby】each_charメソッドについて

## each_charメソッドについて
```ruby
"hello世界".each_char {|c| print c, ' ' }
```
```
h e l l o 世 界
```
このように表示されるらしい。

### 参考
https://docs.ruby-lang.org/ja/latest/method/String/i/each_char.html
データベース 正規化

学習ログです。

# 正規形
DBで保持するデータの冗長性を排除し、一貫性と効率性を保持するための**データ形式**。

情報の重複によるムダ（冗長性）、データの不整合（非一貫性）を解決するための方法が**正規化**。

# 第1正規形
一つのセルの中には一つの値しか含まない状態。
その値のことを**スカラ値**という。

## 表1　第1正規形
| **会社コード** | 会社名 | **社員ID** | 社員名 | 年齢 | 部署コード | 部署名 |
| -- | -- | -- | -- | -- | -- | -- | 
| 001 | Aシステム | 00A | 阿笠 | 30 | D1 | 開発 |
| 001 | Aシステム | 00B | 伊藤 | 20 | D2 | 営業 |
| 002 | Bコンサル | 00A | 内海 | 40 | D3 | 人事 |
| 002 | Bコンサル | 00F | 江藤 | 50 | D1 | 開発 |
| 002 | Bコンサル | 00F | 江藤 | 50 | D4 | 総務 |

# 第2正規形
テーブル内で部分関数従属を解消し、**完全関数従属**のみのテーブルである状態。
異なるレベルのエンティティをテーブルとして分離する作業ともいえる。

## 関数従属性とは
X列の値を決めれば、Y列の値が一つに決まる

```
{X} → {Y}
```

## 部分関数従属とは
主キーの**一部の列**に対して従属する例がある状態。
表1の例だと、このテーブルの主キーは会社コードと社員IDの二つであるが、会社名は会社コードに従属している。

## 完全関数従属とは
主キーを構成する**全ての列**に従属性がある状態。

## 表2 第2正規形

社員テーブル
| **会社コード** | **社員ID** | 社員名 | 年齢 | **部署コード** | 部署名 |
| -- | -- | -- | -- | -- | -- |
| 001 | 00A | 阿笠 | 30 | D1 | 開発 |
| 001 | 00B | 伊藤 | 20 | D2 | 営業 |
| 002 | 00A | 内海 | 40 | D3 | 人事 |
| 002 | 00F | 江藤 | 50 | D1 | 開発 |
| 002 | 00F | 江藤 | 50 | D4 | 総務 |

会社テーブル
| **会社コード** | 会社名 |
| -- | -- |
| 001 | Aシステム |
| 001 | Bコンサル |

# 第3正規形
推移的関数従属をなくした状態

## 推移的関数従属とは
テーブル内部に存在する階層的な従属関係

表2には下記の関数従属が残っている。

```
{部署コード} → {部署名}
```

また、社員IDと部署コードの間にも関数従属が存在している。

```
{会社コード, 社員ID} → {部署コード}
```

つまり全体としては

```
{会社コード, 社員ID} → {部署コード} → {部署名}
```

という二段階の関数従属が存在する。
これを**推移的関数従属**と呼ぶ。

## 表3 第3正規形
社員テーブル
| **会社コード** | **社員ID** | 社員名 | 年齢 | **部署コード** |
| -- | -- | -- | -- | -- |
| 001 | 00A | 阿笠 | 30 | D1 |
| 001 | 00B | 伊藤 | 20 | D2 |
| 002 | 00A | 内海 | 40 | D3 |
| 002 | 00F | 江藤 | 50 | D1 |
| 002 | 00F | 江藤 | 50 | D4 |

会社テーブル
| **会社コード** | 会社名 |
| -- | -- |
| 001 | Aシステム |
| 001 | Bコンサル |

部署テーブル
| **部署コード** | 部署名 |
| -- | -- |
| D1 | 開発 |
| D2 | 営業 |
| D3 | 人事 |
| D4 | 総務 |

# 参考文献
この記事は以下の情報を参考にして執筆しました。

達人に学ぶDB設計徹底指南書
【Lightbox2】ポップアップ画像の枠を消す方法

## はじめに
ここでは「ポップアップ画像の枠を消す方法」のみを紹介するため、Lightbox2を用いたポップアップ画像の作り方については以下を参照

https://qiita.com/probabilityhill/items/70bfad7d6c0034228493


## 方法
CSS（またはStylusなど）に以下のようなコードを追加する

```css:CSSの例
#lightbox .lb-image {
  border: none;
}
```

```sass:Stylusの例
#lightbox .lb-image
  border: none
```

## 全体のコード例とプレビュー
+ 「View Compiled」を押すと Pug -> HTML、Stylus -> CSS に切り替わる
+ 「0.5x」で見ることを推奨
+ GitHubにもコードあり（[こちら](https://github.com/probabilityhill/popup-lightbox2)）
<p class="codepen" data-height="392" data-theme-id="dark" data-default-tab="html,result" data-slug-hash="dyZrzNG" data-user="probabilityhill" style="height: 392px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/probabilityhill/pen/dyZrzNG">
  Delaunay Triangulation</a> by Probability Hill (<a href="https://codepen.io/probabilityhill">@probabilityhill</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>
vscodeでgit worktreeを使う

# この記事は何？

gitにはworktreeという便利な機能がある。
https://qiita.com/yoichi22/items/8f92110f24690ca8966f

worktreeを使えば、ディレクトリの移動によってブランチを切り替えることができるようになる。

最近(2022年1月頃)まで、このworktreeはvscodeで使うことができなかった。
そのため数多くのvscode愛好家はworktreeの使用を断念していた(はず)。

そして、念願のworktreeのvscodeエクステンションが2022年2月にリリースされた。
この記事ではエクステンションを利用して、worktree機能をvscodeで使用できるか確認する。


# 使用するエクステンション

[Switch Git Worktree](https://marketplace.visualstudio.com/items?itemName=chrisdicarlo.vscode-switch-git-worktree)をインストールしておく

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435280/6618438a-0050-3f77-37e8-ac535f64b13c.png)


# 試す

以下のようなブランチ構成がある。

```
❯ git branch -a
  common
* master
  prd
  remotes/origin/HEAD -> origin/master
  remotes/origin/common
  remotes/origin/master
  remotes/origin/prd
  ```

要するにローカルにもリモートにもmaster/prd/commonといった3つのブランチがある状態である。

```
> pwd
/test/myrepo

❯ git worktree add ../prd prd
> git worktree add ../common common
```

prdとcommonブランチのworktreeを親ディレクトリにぶら下げた

```
/test
├── myrepo
│   ├── README.md
│   └── src
├── common
│   └── src
└── prd
    └── src
```


vscodeにてレポジトリのディレクトリ(今回の場合は/test/myrepo)を開く
この時点ではカレントブランチがmasterになっている

コマンドパレットにて"Switch Worktree"を入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435280/836bb582-b7b1-d53e-b1eb-b2cc31da5374.png)

移動可能なworktreeが表示されるため、移動したいworktreeを選択する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435280/203ad478-646d-df88-c29e-ab9adc20abfc.png)

今回はcommonを選択する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435280/1239f4a1-ed20-9816-fab4-29a081b1b843.png)

そうすると一度vscodeがリロードされて、worktreeとして登録されたディレクトリ(/test/common)が開かれる。ブランチもSwitch Worktreeで指定したcommonに切り替わっている。

以上のことから、Switch Git Worktreeエクステンションを使いvscodeでworktreeが使えることがわかった。
annotate_modelsでmigrationの度に自動でアノテーションを作成させる方法

# 環境
Ruby 3.0.2
Rails 7.0.2.3

# Annotate models

モデルファイルなどに、↓のようなマイグレーションの内容を自動で書いてくれるツール

```ruby
# == Schema Info
#
# Table name: line_items
#
#  id                  :integer(11)    not null, primary key
#  quantity            :integer(11)    not null
#  product_id          :integer(11)    not null
#  unit_price          :float
#  order_id            :integer(11)
#

class LineItem < ActiveRecord::Base
  belongs_to :product
  . . .
```

[ここ](https://github.com/ctran/annotate_models#install)を参考に導入しました。

# 動かない
```ruby
rails db:migrate
```
migration実行すると動作してくれるはずなのにアノテーションが書かれない。

# 解決
公式のREADMEを読むと、
> To automatically annotate every time you run db:migrate, either run rails g annotate:install or add Annotate.load_tasks to your Rakefile.

と書かれてたので、そのとおり実行。

```ruby
rails g annotate:install
```

無事に作成されました。
しっかりドキュメントにも目を通さないといけないですね。

https://www.rubydoc.info/gems/annotate/3.0.3

https://github.com/ctran/annotate_models#install
ローカル環境ブラウザからリモートサーバ上で立ち上げたJupyterを使用する

ここではリモートサーバ上(Cent OS)でJupyter NoteBookを立ち上げ、ローカル環境のWebブラウザからアクセスして使用する方法を記載します。


# 1.Jupyterのインストールと設定
ここではJupyterのインストールとリモート接続するための初期設定を行います。

いつも通り何かしらの手段(anacondaやpyenv等)で仮想環境を構築後、以下のコマンドで`jupyter`をインストールします。

```bash
pip install jupyter
```
その後、以下のコマンドを入力しconfigファイルを作成するとホームディレクトリ以下に`~/.jupyter/jupyter_notebook_config.py`が作成されます。

```
jupyter notebook --generate-config
```

このファイルの各々の該当行のコメントアウトを外し以下のように編集します。なお、`port=58888`は任意の番号で構いません。以降、こちらの番号で一貫して設定を行っていきます。それ以外はコメントアウトされたままで大丈夫です。

```
c.NotebookApp.ip = '*'
c.NotebookApp.open_browser = False
c.NotebookApp.port = 58888
```

設定が終わったら、以下のコマンドでjupyter notebookを立ち上げておきましよう。下部にNotebookアクセス用のURLが出てくるはずです。
```bash
    To access the notebook, open this file in a browser:
        file:///mnt/data1/furukawa/.local/share/jupyter/runtime/nbserver-42980-open.html
    Or copy and paste one of these URLs:
        http://cosmos:58888/?token=528e6ae613ce32560a41602b9989bea493207eef38d2393c
     or http://127.0.0.1:58888/?token=528e6ae613ce32560a41602b9989bea493207eef38d2393c
```

# 2.Jupyter NoteBookを公開するためのリモートサーバのポートの開放
リモートサーバ上で立ち上げたJupyter NoteBookにアクセスするために必要なポートの開放を行います。尚、OSによってこの方法は異なるため、各々に合わせた設定が必要になります。

ここでは、`/etc/sysconfig/iptables`にポート開放のための文を追記することにより実現します。`sudo vi /etc/sysconfig/iptables`等で編集可能な上でファイルを開き、以下の文を追記します。
```
-A INPUT -p tcp --dport 58888 -j ACCEPT
```

次に、以下を実行し編集を反映させます。
```
service iptables restart
```

最後に以下のコマンドで58888のポートが解放されたかを確認して完了です。jupyter notebookが立ち上がっており、かつポートが解放されていれば、以下のようになっているはずです。
```
# lsof -i -P
~
jupyter-n 42023  user    5u  IPv4 49594839      0t0  TCP *:58888 (LISTEN)
jupyter-n 42023  user    6u  IPv6 49594840      0t0  TCP *:58888 (LISTEN)
~
```

# 3.リモートサーバで立ち上げたJupyterにローカル環境のブラウザから接続
リモートサーバ側でnotebookを立ち上げた後、URLをコピペしてブラウザに張り付ければアクセスできます。

ここで幾つかの想定されるエラーがあり、私も遭遇しました。

## 想定されるエラー1
`DNS_PROBE_FINISHED_NXDOMAIN`がブラウザ上で出るエラーです。これはURLをリモートサーバのホスト名で指定してアクセスした際に起こるものでDNSサーバが名前解決出来ていないことによって起きています。DNSサーバに接続できているかを見直すか、直接IPアドレスを指定してURLを指定すると回避できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385803/c963bcd7-9d63-0d07-6472-c4d584e6171d.png)


## 想定されるエラー2
エラー1を直したところ、今度は`ERR_CONNECTION_REFUSED`のエラーが出ました。何かしらが原因でアクセスが拒否されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385803/07554798-aec3-0496-a333-b1e4c2fc8b0b.png)

キャッシュ周りが原因でエラーが起こっているのですが、詳細な原因は不明なままでした。対策方法としては、[ここのさいと](https://kinsta.com/jp/blog/err_connection_refused/#what-is-err_connection_refused)にあるように、以下をブラウザのURL欄に貼り付け、キャッシュの削除を行います。
```
chrome://settings/clearBrowserData
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385803/c1dfa815-9d0e-33ae-7207-ce80e063d33b.png)

# 接続完了
無事接続できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385803/a1a10340-d025-7e85-f7e1-10678b458aff.png)
本番環境でのassets:precompile未実施エラー/ 初めてのAWS忘備録④

前回の続き→ [EC2内の環境構築【デプロイ】/ 初めてのAWS忘備録③](https://qiita.com/mmaumtjgj/items/7e169e1d715ba1876b99)

```
[ec2-user@ip... アプリ名]$ bundle exec puma -C config/puma/production.rb -e production
```
上記コマンドでアプリを起動させたは良いものの、実際の画面を見てみるとこのようなエラーが出た。
[![Image from Gyazo](https://i.gyazo.com/fb584365f396fe879a701e0db59ffbf7.png)](https://gyazo.com/fb584365f396fe879a701e0db59ffbf7)

エラーログを見にいくと、
``ActionView::Template::Error (The asset "application.css" is not present in the asset pipeline.):``
とあった。アセットされた**application.css**がないらしい。

``production環境``では自動で``css``や``js``をコンパイルしてくれないので（デフォルト設定がそうなっているので） 自分でプリコンパイルする必要があるそう。

```
[ec2-user@ip... アプリ名]$ bundle exec rails assets:precompile RAILS_ENV=production
```

``public/assets/``配下にプリコンパイルされたアセットが存在することを確認。
```
[ec2-user@ip... アプリ名]$ cd public/assets/
[ec2-user@ip... アプリ名]$ ls
application-111ac35321e379f53529ace176fe931c952be73f7ffd688b815ec21878126685.js
application-111ac35321e379f53529ace176fe931c952be73f7ffd688b815ec21878126685.js.gz
application-e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.css
application-e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.css.gz
```

次に、``config/environments/production.rb``内にある
```config/environments/production.rb
config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
```
の値が``false``の場合、public配下のファイルが公開されないので、``true``にするとうまく行く。

しかし直接``true``直書きは良くないので、エラーが出るのは、``ENV['RAILS_SERVE_STATIC_FILES']``に値が入っていないのが原因なので、ターミナルから変数を渡すことで``true``にする。

```
[ec2-user@ip... アプリ名]$ export RAILS_SERVE_STATIC_FILES=true
```

``Nginx``と``puma``の再起動すれば反映される。

## 参考記事
[【Rails】本番環境におけるアセットプリコンパイルの設定](https://qiita.com/aiandrox/items/408724ab8a4482fb5873)
[Rails5でnginx+pumaでproduction環境を構築する](http://blog.atwata.com/middle/2017/09/30/rails5-nginx-puma.html)
【開発工程】１．要件定義

**＜開発工程＞**
---
<font color="Red">**１．要件定義（RD、Requirement Definition）**</font>
<font color="Gray">２．基本設計（BD、Basic Design）
３．詳細設計（DD、Detail Design）
４．開発（CD、Coding, Development, Programming）
５．テスト（Test）
　５－１．単体テスト（UT、Unit Test）
　５－２．結合テスト（IT、Intergration Test）
　５－３．システムテスト（ST、System Test）
　５－４．ユーザ受け入れテスト（UAT、User Acceptance Test）
６．リリース（Release）、移行（Migration）
７．運用（Operation）
８．保守（Maintenance）</font>


１．要件定義（RD、Requirement Definition）
---
**１．定義**
ユーザ（顧客）ニーズを纏めて実現したものを定義する工程。
- ユーザ（顧客）：こういうことがしたいな～　**【ニーズ】**
- 開発者：こういうシステムを構築してこのように運用するのはいかがでしょうか？　**【要件定義】**
<br/>

**２．主な項目**
- 要件の定義：ユーザニーズの整理　
- 機能要件の定義：ユーザニーズから開発出来る、開発する内容の整理
- 非機能要件の定義：ユーザニーズから開発出来ない、運用に回す内容の整理
<br/>


**３．まとめ**
要件定義工程はプロジェクトを成功を左右するもっとも重要な工程であり、
正しく<font color="Red">「ユーザ（顧客）ニーズを把握し」、「何を開発するか」、「何を運用に回すか」</font>を明確に整理（文書化）する工程。
<br/>
テスト計画の策定

# テスト計画の策定
## テスト計画の構成は三つに分かれる
そのテストが成功するか、それとも失敗してしまうか、多くはテスト計画で決まると言って、過言ではありません。
テスト計画とは、テストの設計、実装、実施、管理といった、テストの全ての活動に対し、指針を定めるものです。
テスト計画の骨格は、以下の三つになります。
1. 要求の整理・分析
- テスト対象・範囲は何か
- テストの目的・目標、重点項目は何か
- テスト対象の開発状況はどうか
- どんな課題やリスクがあるか
1. 要求の実現方法
- テストはどんな組み立てで行うか
- ツールや環境はどんなものが必要か
- テストプロセスで生成する成果物は何か
- 各種基準や目標の詳細
- 体制・役割分担・作業場所
- スケジュール
1. 各種管理の計画
- 課題管理、リスク管理
- 不具合管理
- 文書やデータの管理
- 進捗管理・コミュニケーション
上記の三つのパートは、違いに関連しあっています。
要求の整理・分析を行うことで、テストに対する要求を正しく理解し、とりま状況を整理し、課題・リスクを抽出します。
要求と状況を整理した上で、課題とリスクを踏まえながら、「2. 要求の実現方法」で実行計画を策定します。
更に、テストをした支えする各種マネジメントの準備を「3. 各種管理の計画」で定義します。

## 要求の整理・分析
「1. 要求の整理・分析」を行うことで、テストに対する要求を正しく理解し、取り巻く状況を整理し、課題・リスクを抽出します。

## 要求の実現方法
要求と状況を整理した上で、課題とリスクを踏まえながら、「2.要求の実現方法」で実行計画を策定します。
### テストのの粒度と実施順序
1. テストに要求されていることを元に、実施するテストタイプ（テストの種類）と粒度、実施順序を定めます。
　- 単機能テストの正常パターンと限界パターン、を優先的に行う
　- 次に、準正常パターン、異常パターン、組み合わせパターンテストをする
　- 性能テストは定期的に行う
　- リグレッションテストは自動テストで常に行う
　このように、個々のテストを設計する前に、テストの全体を設計します。
ここで注意すべき点は「実施するテスト」を計画するだけでなく、「実施しないテスト」も計画することです。
### 使用する機材、ツール・環境
テストで使用する機材、ツール・環境は多岐に渡ります。
1. テスト設計に用いるもの
- テスト実施に用いるもの
-　不具合報告、管理、分析に用いるもの
-　進捗管理、各種管理に用いるもの
-　構成管理、文書管理に用いるもの
これらを明らかにするとともに、機材の調達や、ツール・環境の準備に必要なタスクを洗い出し、計画に落とし込みます。
- ライセンスの取得、ID登録の数やタイミング
- 機材、ツール・環境のセットアップ、初期動作確認
- テストデータの調達、作成
- 不慣れなメンバーがいる場合、レクチャーと必要に応じてリハーサル
これらの準備は、意外にも時間も労力もかかります。あらかじめ計画しておかないと、後で突貫的に作業することが余儀なくされ、悪くすればテストの遅延が生じることになります。
### 成果物の定義
テストの成果物は、テストの各種プロセスからのアプトプットであり、さまざまなものがあります。
1. テスト計画プロセスからのアウトプット
- テスト計画書
1. テスト設計プロセスからのアウトプット
- テスト設計仕様書
- 機能動作確認一覧
- テストマップ
- テスト明細
1. テスト実装プロセスからのアウトプット
- テストデータ
- テストケース
1. 問題解決プロセス
- バグ表
- 課題表
- リスク表
1. 進捗管理・品質管理プロセスからのアウトプット
- 各種計測データと、そこから導き出される分析データと見解
- 進捗報告、品質分析報告
1. テスト終結プロセス
サマリーレポート
### 基準・目標
1.　テスト開始基準
テスト対象の〇〇テストが実施され、不具合回収が完了している
テスト開始以降判断のためのプレテストOK率が００以上
客先のテスト移行判断判定会議で承認されている
1. テスト中断基準
高頻度で頻発したり、テスト対象のリリース遅れなどにより、単位期間あたりのテスト実施率が００以下、OK率が００以下
1. テスト再開基準
テスト再開判断のためのプレテストの、OK率が００以上
1. テスト完了基準
テスト実施率100%、OK率100%、バグ回収率100%
上記に満たない場合、顧客の承諾が得られている
不具合状況を分析し、強化テスト等の対策が実施されている
## 各種管理の計画
テストをすこうする主軸は、計画、設計、実装、実施のプロセス。
これらのプロセスを円滑に的確に運用するために、各種管理の準備・計画を行います。
1. 課題管理・リスク管理
課題管理・リスク管理の方法
1. 不具合管理
使用するツール、BTS運用ルール、顧客連携
1. 文書・データの構成管理
文書の識別管理、変更管理、配付管理、保管方法
1. 変更管理
仕様変更、スケジュール変更の窓口、対処方法
1. トレーサビリティ管理
仕様/設計/テスト項目とのトレーサビリティの取り方を定義
1. 進捗管理・コミュニケーション
進捗フォーマット、報告頻度・ルート、意思疎通
1. 機材・資材管理
テスト機材、テスト環境、顧客支給品
1. レビュー計画
テストプロジェクトの成果物のレビュー
1. トレーニング計画　
各種トレーニングの必要、対象、方法、時期
1. その他プロジェクト内規約
その他、プロジェクト内で共有すべきルール
## まとめ
- 要求の整理・分析
- 要求の実現方法
- 各種管理の計画
ポイントは、計画策定やテスト設計を行う前に、テストに対する要求を正しく理解し、取り巻く状況を整理することです。
要求を正しく理解し、状況を整理した上で計画を策定すると、考慮の漏れ抜けが防止でき、課題やリスクに対して配慮が行き届き、マネジメント力が向上します。つまり、テスト計画はテストへの要求をもとに、テスト設計や管理の個別の事項に橋渡しをする、重要な役割を持っているのです。
How to use bind mounts


# MEMO 

```
 docker run -d \
  -it \
  --name devtest \
  --mount type=bind,source="$(pwd)"/target,target=/app \
  nginx:latest
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1689380/3bcffd5f-a8a5-b9c7-b811-48f2f1d432ce.png)
RSpec導入手順 コントローラテスト

## 序文

RSpecを初めて使ってみましたので手順を残します。

### コントローラを作りましょう

```
class Api::V1::TheDogController < ApplicationController

  def index
    render json: { breed: 'shepard'}
  end

end
```

route.rbのパスを通しましょう。


## Gemfileにrspecを入れましょう
```
group :development do
   gem 'rspec-rails'
end
```

## specファイルを作りましょう
```
rails g rspec:install 
rails g rspec:controller the_dog

```

```
require 'rails_helper'

RSpec.describe Api::V1::ThdDogController do
  render_views
  describe "GET /index" do
    it do
      request.env["HTTP_ACCEPT"] = 'application/json'
      get :index, format: :json, params: { call: "oh my dog"}
      json = JSON.parse(response.body)
      p json
      expect(json["breed"]).to eq "shepard"
    end
  end
end
```

## テスト環境設定

テスト環境の設定ができているか見直しましょう. 
環境依存ですが、筆者の場合は下記が必要でした
- config/database.ymlにテスト用のDBを指定 
- credetialのtest.yml.encの設定
- config/settings/test.yml
- rails db:environment:set RAILS_ENV=test

## テスト実行
```
bundle exec rspec
```
はじめてflutterを使ってみて

自分がflutterを使ってみた所感をつらつらと書いていこうと思います。

## Flutter概要

![flutter.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2242071/c764c15c-0ff1-3e10-95c1-731f1adcab91.png)

2017年にGoogleが発表したオープンソースのモバイルアプリケーションフレームワーク。

Flutterを用いれば、iOS/Android/Webなどを全く同じコードで開発することができます。
ただしiOSをシミュレートするにはMac必須（AndroidはWindows, Macの両方できる）。
現状、Webはあまり実用的ではないようです。(実行速度が遅い、SEO対策ができないetc...)

言語はDartを使用。

2021年5月の時点で、過去30日でリリースされたGooglePlayの1/8のアプリがFlutterでできているそうです。

## Dartについて軽くお勉強

Dartは元々JavaScriptの問題点を解決させた後継言語を目的に設計されているので、エンジニアには馴染みのある文法がよく見られます。
また、クラスベースのオブジェクト指向をサポートしており、中〜大規模開発に適していると言われています。

まずは触ってみましょう。
[dartpad](https://dartpad.dev) を利用すれば簡単にDartで遊べます。

初めてアクセスする場合、以下のようになっていると思います。Runをクリックすれば右側に結果が表示されます。

![スクリーンショット 2022-03-17 15.55.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2242071/f2aea1db-434d-5b5a-63aa-982608193388.png)

### Dartの変数と関数の扱い方

変数の指定はCやJavaと同じ様に指定します。
```dart
// [変数の型] [変数の名前] = [代入する値];

// 例
int age = 19;
String name = "tarou";
```

関数の定義は以下のように指定します。
```dart
// [返り値の型] [関数の名前]（[引数]） {
// 	return [返り値];
//     }

// 例
int fibonacci(int n) {
  return n < 2 ? n : (fibonacci(n - 1) + fibonacci(n - 2));
}
```

関数の例に使ったfibonacch()はdartpadの右上にsampleから「fibonacci」を選択し、表示されたサンプルから拝借しました。
他にもサンプルがいろいろあるので是非見てみてください。（個人的お気に入りはSunflower）

### 練習問題

Dartに慣れてみましょう。実際に自分もやった問題です。

_Q1. 
引数 x, y をとり x + y の計算結果を返すadd関数を作成する。
x, yは整数をとる。
main関数からadd関数に24, 34を渡して58を出力する。_

.
.
.
.
(思考中)
.
.
.
.

できましたか？解答の一例を見てみましょう

### 解答

```dart
void main() {
  print(add(24, 34));
}

int add(int x, int y) {
  return x + y;
}
```

なんかみたことあるなぁ〜くらいの文法だったのではないでしょうか。



## FlutterのHelloWorld

Flutterに話題を戻します。

### Flutterのコード構造

FlutterはWidgetと呼ばれるコンポーネントの組み合わせによって画面を構築しています。
さらにそのWidgetをツリー状に組み合わせることでUIを実現しています。

例えば、dartpadのsampleからCounterを選択しましょう。
これはFlutterを初めてインストールした際の最初のコードと同等です。いわゆるHello Worldですね。
この構造はこのようになっています。

![tree.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2242071/406ba3c6-7b52-941e-9451-3aee9fa2152c.png)

### ソースコードをみていく

下記順番で呼ばれていきます。

- main関数 
- runApp() 
- MyApp 
- MyHomePage
- MyHomePageState

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2242071/bc9f75ce-5069-6397-98ed-d7c9a36d4381.png)

紫：インポート文

青：main関数
runAppを呼び出しているだけ

緑：MyApp
アプリのタイトルや色のテーマを決め、画面の中身を呼び出している


![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2242071/b79ef28a-24e9-389d-fc6e-ec36c0b57748.png)

茶色：MyHomePage
状態管理を利用、今回ので言えばプラスボタンを押したら数字の状態が増えていく。
状態管理を行うことで、画面の更新ではなくWidgetごとに更新することができる。
今はRiverpodを使った状態管理が主流かも（？）

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2242071/6aa1f3e2-6023-f78b-7369-4b088ace9da8.png)

黄色：MyHomePageState
実際の画面の中身の部分。
AppBarが上に表示されている青いバー。
その下bodyから入れ子構造になっているのがなんとなくわかると思う。

## まとめ

「Dart言語を使っていて、クロスプラットフォームで開発ができるんだな〜」とだけ覚えてもらえれば！
バージョン指定で"rails new"したら"Gem::GemNotFoundException"でコケたとき用

# そもそも
- 現場Railsの3章、"taskleaf"アプリケーションの準備段階で躓く（バージョン指定でnewが出来ず）
- バージョン指定での"rails new"以外の方法があるっぽいので実践してみたログ

# 手順
#### アプリのディレクトリを作成する
```
mkdir hoge
```

#### ディレクトリに移動
```
cd hoge
```

#### bundle initする
- （これ要るのか？要調査）
```
bundle init
```

#### できたGemfileにRailsのバージョンを書き込む
```rb:Gemfile
gem "rails", '5.2.1'
```

#### bundle installする
```
bundle install
```

#### Rails new（質問にはYで答える）
```
$ rails _5.2.1_ new . -d postgresql --skip-bundle
```

#### Gemfileのsass-railsのバージョン指定を外す
- 次にbundle installする時にエラーが出るため
```rb:Gemfile
gem 'sass-rails'
```

#### bundle installしようとするも、"pg"がインストールできずにコケたので対策
- エラーメッセージを辿ると、"pg_config"が見つからなかったようでした
- 解決するのに2時間はかかった
```:pg_configを探す
find / -name pg_config
```
```:postgresqlをビルドする時に参照するパスを変更
bundle config build.pg --with-pg-config=/opt/homebrew/Cellar/postgresql/14.2_1/bin/pg_config
```

#### bundle install
- 通ったときの喜びはひとしお
```
bundle install
```

#### omake
```:PostgreSQL起動停止確認コマンド
brew services start postgresql
brew services stop postgresql
brew services list
```

# 疲れた
#### Rails Tutorial完走→現場Railsに入ったばかりのナメクジ並感
- もしかして、環境構築って鬼門なのでは？
- 2度と同じ轍を踏まないようにしよう
- こうやってやったことログを残すのが楽しいことに気づいた
- これからもよろしくお願いします

# 参照
https://teratail.com/questions/89270

https://qiita.com/kodai_0122/items/56168eaec28eb7b1b93b#bundle-install---path-vendorbundle%E3%81%A7an-error-occurred-while-installing-pg-122%E3%81%A8%E3%81%84%E3%81%86%E3%82%A8%E3%83%A9%E3%83%BC%E3%81%8C%E5%87%BA%E3%81%9F%E5%A0%B4%E5%90%88

https://qiita.com/terufumi1122/items/03edf05d4c940c361712

https://elastictechdays.info/rails-postgresql-bundle-install-error/

https://hacknote.jp/archives/30385/

https://qiita.com/sf213471118/items/0e843af332ea0210c810
Google map APIで特定の周辺の詳細データを取得のやり方

# 1.環境

ブラウザ　：　Google Chrom
言語　　　：　GoogleAppsScript


# 2.前提
Google mapのAPIをキーを取得していること


# 3.東京駅周辺のレストランの情報を取得

```
function map_data() {

  //東京駅の周辺の緯度と軽度を検索を取得する
  var geocoder = Maps.newGeocoder();
  geocoder.setLanguage('ja');
  var response = geocoder.geocode('東京駅')

  // 経度
  var lat = response['results'][0]['geometry']['location']['lat'];
  // 緯度
  var lng = response['results'][0]['geometry']['location']['lng'];

  var URL = '';

  //GoogleのAPIキー
  var KEY = 'key=' + '';
  //GETで取得する
  var URL_1 = 'https://maps.googleapis.com/maps/api/place/nearbysearch/json?'
  // 緯度と経度を設定する
  var LOCATION = '&location=' + String(lat) + ',' + String(lng); 
  // 緯度と経度から半径５００メートルに設定
  var RADIUS = '&radius=' + '500';
  // 検索する情報を料理店を設定
  var TYPE = '&type=' + 'restaurant';
  //関連情報を設定する
  var KEYWORD = '&keyword=' + '東京駅';
  // 取得情報を日本語のみに設定する
  var LANG = '&language=' + 'ja';

  var URL = URL_1+KEY+LOCATION+RADIUS+TYPE+KEYWORD+LANG;
  var res = UrlFetchApp.fetch(URL);
  // jsonデータで取得する
  var json = JSON.parse(res.getContentText());

  //取得情報を入れる配列
  var c = [];

  
  for(let i = 0; i < json['results'].length; i++){
    c.push([
        // 店名
      json['results'][i]['name'],
      // 県
      json['results'][i]['plus_code']['compound_code'].split('、')[1],
      // 住所
      json['results'][i]['vicinity']
    ]);
  }
  
  // 次のページのトークンを取得する
  var NEXT_PAGETOKEN = json['next_page_token'];

  
  while(true){
    
    if (typeof NEXT_PAGETOKEN == "undefined" || NEXT_PAGETOKEN == '') {
      break;
    }

    var URL = '';
    var URL_2 = 'https://maps.googleapis.com/maps/api/place/nearbysearch/json?'
    var PAGETOKEN = '&pagetoken=' + NEXT_PAGETOKEN;

    var URL = URL_2+KEY+PAGETOKEN;
    var res = UrlFetchApp.fetch(URL);
    var json = JSON.parse(res.getContentText());
  
    for(let i = 0; i < json['results'].length; i++){
      c.push([
          // 店名
        json['results'][i]['name'],
        // 県
        json['results'][i]['plus_code']['compound_code'].split('、')[1],
        // 住所
        json['results'][i]['vicinity']
      ]);
    }
    NEXT_PAGETOKEN = json['next_page_token'];
  }


  Logger.log(c)
}

```

店名と県と住所をコンソールに表示する。
住所の一覧から緯度・経度を取得する

## はじめに
膨大な住所の一覧をもとに緯度と経度を取得したいということで「Googleマップで住所検索⇒検索されたポイントを右クリック⇒緯度・経度取得」でも取得はできるのですが、手間がかかりすぎるため一括で取得するために[Geocoding API](https://github.com/madefor/postal-code-api)を利用してみました。

## サンプルコード
```html:Geo2LatLon.html
<html>
<head>
  <title>Geo2LatLon</title>
  <!-- referrence by https://github.com/madefor/postal-code-api -->
  <style>
    textarea{width:100%;}
    input{margin-top:5px;padding:5px 20px 5px 20px;font-weight:bold;font-size:20px;}
  </style>
  <script src="https://cdn.geolonia.com/community-geocoder.js"></script>
</head>
<body>
  <h2>Geo2LatLon</h2>
  <h3>概要：住所から緯度経度を取得するツールです。</h3>
  <h3>使い方</h3>
  <ol>
    <li>テキストエリアに住所を入力します。複数の場合は改行区切りで入力してください。</li>
    <li>「実行」ボタンを押下します。</li>
    <li>csv形式でファイルがダウンロードされます。</li>
  </ol>
  <textarea id="geoList" rows="20"></textarea>
  <input id='exec' type='button' value='実行' />
  <script>
    document.getElementById('exec').addEventListener('click', () => {
      const geoList = document.getElementById('geoList');
      if (geoList.value) {
        const lines = geoList.value.split('\n');
        const promises = [];
        for (let i = 0; i < lines.length; i++) {
          const addr = lines[i];
          if (addr) {
            const func = new Promise((resolve, reject) => {
              getLatLng(addr, (geo) => {
                const data = [addr, geo.lat, geo.lng].join(',');
                resolve(data);
              });
            });
            promises.push(func);
          }
        }

        Promise.all(promises).then((results) => {
          results.unshift(['住所', '緯度', '経度'].join(','))
          const data = results.join('\n');
          const filename = 'geo2latlon.csv';
          const bom = new Uint8Array([0xef, 0xbb, 0xbf]);
          const blob = new Blob([bom, data], {type: 'text/csv'});
          const url = (window.URL || window.webkitURL);
          const download = document.createElement('a');
          download.href = url.createObjectURL(blob);
          download.download = filename;
          download.click();
          url.revokeObjectURL(url);
        });
      }
    });
  </script>
</body>
</html>
```

ただ精度はあまり良くないようなので（Google Maps APIも同様）、Google Mapsの右クリックで取得するのが一番良さそうです。。。
Vue CLIとは

# Vue CLIとは
**Vue.js**での開発を支援してくれる便利なツールのこと。例えば以下のようなことをしてくれる。
・プロジェクトサンプルの生成
・webpackなどのバンドル環境設定
・Vueifyや単一ファイルコンポーネントの環境設定
・変更の差分だけサーバを更新
ここで、**CLI**とは**Commnad Line Interface**の略で、コマンドラインを使って開発を行うためのツールのこと。

# インストール
**Vue CLI**のインストールは``npm``を使って以下で行うことができる。
```
npm install -g @vue/cli
```
また、プロジェクトの作成は以下で行う。
```
vue create <プロジェクト名>
```
上記コマンドを実行すると、様々な設定が行える。
**Vue CLI**は、プロジェクトを作成するとサンプルが入っているため以下のコマンドを実行して``http://localhost:8080/``にアクセスすると入っているサンプルが表示される。
```
cd <プロジェクト名>
npm run serve
```
Google Chromeを別セッションで開く方法

## はじめに
Google Chromeは最近ではタブグループなども充実して便利に利用することができるようになってきていますが、仕事用と趣味用などそもそも用途によって別のセッション（別画面）で使い分けたいこともあるかと思います。
そんな時に以下の対応だけで簡単に使い分けをすることが可能です。

## 対応手順
### 1. ショートカットをコピー
1. スタートメニューを表示します。
1. 「Google Chrome」を右クリックします。
1. 「ファイルの場所を開く」を選択します。
1. 表示されたフォルダにあるショートカットを任意の場所（デスクトップなど）にコピーします。

### 2. プロパティ編集
1. コピーしたショートカットを右クリックします。
1. 「プロパティ」を選択します。
1. 「リンク先」を以下に設定します。
```
--user-data-dir="%userprofile%¥AppData¥Local¥Google¥Chrome¥User Data¥Default2"
```
```Data¥Default2```部分が対象セッションの情報保存先になります。
ここを変えてあげれば必要に応じてセッションを増やすことができます。
ファイルサーバーへの接続バッチ

## はじめに
最近ではクラウドが主流になっているので活用機会は減ってしまっているかもしれませんが、ファイルサーバーを利用されている方向けの内容となっております。
ファイルサーバーへの接続時に毎回ユーザーIDやパスワードを入力するのは面倒ですよね。
そんな時に以下のバッチファイルを作成してしまえば面倒な入力は一切不要になります。
当然、Windows資格情報に保存してしまえば自動で接続することができますが、そうはいかない環境や認証情報を切り替えなければいけない環境の場合に重宝されるかと思います。

## サンプルコード
``` server_connect.bat
@echo off

set host=[ip or servername]
set user=[username]
set pass=[password]
for /f %%A in ('net use ^| find /c "%host%"') do set RESULT=%%A
if "%RESULT%"=="0" (
net use \\%host% /user:%host%\%user%%pass% /persistent:no
)

explorer \\%host%
```
**ファイル内に認証情報を直接記載するのでファイルの取り扱いには充分ご注意ください。**
スタートアップで実行するなどすればPC起動時に自動で接続してくれます。
ショートカットでの実行も可能です。（ショートカットについては[こちら](https://qiita.com/oj_free_oj/items/6eb59efd2fd2e275e852)）
リモートデスクトップ接続バッチ

## はじめに
リモートデスクトップ接続って毎回IDやパスワードを入力しなければならず、ちょっと面倒ですよね。
そんな時はバッチファイルを作成して少しでも手間を減らしましょう。

## サンプルコード
``` connect_rdp.bat
@echo off

set server=[ip or servername]
set userid=[domain\username]
set passwd=[password]

Cmdkey /generic:TERMSRV/%server% /user:%userid% /pass:%passwd%
Start mstsc /v:%server%
Timeout 30
Cmdkey /delete:TERMSRV/%server%
```
**ファイル内に認証情報を直接記載するのでファイルの取り扱いには充分ご注意ください。**
ショートカットでの実行も可能です。（ショートカットについては[こちら](https://qiita.com/oj_free_oj/items/6eb59efd2fd2e275e852)）
URLデコードバッチ

## はじめに
パスに日本語が入ったURLをコピーするとブラウザが自動でエンコードしてくれて共有しやすくなっていますが、パス自体を参照したい場合などにはこれが邪魔だったりすることがあります。
そんな時に以下のスクリプトで簡単にデコードしてしまいましょう。

## サンプルコード
``` url_decode.wsf
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<package>
    <job>
        <script language="JavaScript">
//<![CDATA[
var getClipboard = function () {
    var ff = new ActiveXObject("Forms.Form.1");
    var tb = ff.Controls.Add("Forms.TextBox.1").Object;
    tb.MultiLine = true;
    if (tb.CanPaste) tb.Paste();
    return tb.Text;
    tb = null; ff = null;
}
var setClipboard = function (text) {
    var ff = new ActiveXObject("Forms.Form.1");
    var tb = ff.Controls.Add("Forms.TextBox.1").Object;
    tb.MultiLine = true;
    tb.Text = text;
    tb.SelStart = 0;
    tb.SelLength = tb.TextLength;
    tb.Copy();
    tb = null; ff = null;
}
//]]>
        </script>
        <script language="JavaScript">
//<![CDATA[
setClipboard(decodeURIComponent(getClipboard()));
//]]>
        </script>
    </job>
</package>
```
使用方法は、クリップボードにURLをコピーして上記スクリプトを実行するだけです。

## おまけ
このままだとスクリプトを実行する手間がかかってしまいます。
なので上記スクリプトを実行するバッチファイルをかましてショートカット実行することも可能です。（ショートカット実行については[こちら](https://qiita.com/oj_free_oj/items/6eb59efd2fd2e275e852)）
``` url_decode.bat
@echo off
cscript %~dp0decode.wsf
```
Windows10のショートカットパス

## はじめに
バッチなどを作成してショートカット利用する場合、Windows7までは環境変数に対象フォルダを登録する必要がありました。
ただ、この方法は基本的に管理者権限が必要なため、環境によっては利用できない方法でした。
しかし、Windows10からはデフォルトでユーザー毎にショートカットフォルダが割り当てられています。
そのフォルダパスを紹介したいと思います。

## ショートカットパス
```
C:\Users\[ユーザー名]\AppData\Local\Microsoft\WindowsApps
```
ただこれだと環境（ユーザー名）が変わるたびに```[ユーザー名]```部分を見直す必要があります。
（環境が変わることがない方であれば特に困ることはないと思いますが・・・）

そんな時のために便利なショートカットパスが以下です。
```
%userprofile%\AppData\Local\Microsoft\WindowsApps
```
```%userprofile%```でログインユーザーのパスのショートカットになります。
この他にも色々と応用できるかとおもいます。
データベース 設計の手順

# 論理設計
概念スキーマを定義する設計。

システム開発におけるデータベース設計は
1. 概念スキーマ（論理設計）
2. 内部スキーマ（物理設計）

の手順で行う。

## ステップ
### 1.エンティティの抽出
エンティティとは「実体」を表す。
例）顧客・店舗・会社員

RDSではこれらを「テーブル」という物理的単位で格納していく。
そのために、システムに**どんなエンティティが必要になるかを抽出**する。

### 2.エンティティの定義
各エンティティが**どのようなデータを保持するか決める**。
エンティティはデータを「属性(attribute)」という形で保持する。

### 3.正規化
エンティティについて、**システムの利用がスムーズに行えるよう整理する**。
更新が整合的に行えるようにする。

### 4.ER図の作成
エンティティ同士の**関係を表現する**図（ER図）を作成する。

# 物理設計
論理設計の結果をもとにデータを格納するための物理的な領域や格納方法を決める工程。

## ステップ
### 1.テーブル定義
論理設計で定義された概念スキーマをもとに、「テーブル」の単位に変換する。
ER図を論理モデルと呼ぶのに対し、ここで作られるものは**物理モデル**と呼ぶ

### 2.インデックス定義
インデックスとは、**キー値とデータへのポインタ**の配列。
SQL文はインデックスを辿ることでテーブルの特定レコードに狙い撃ちでアクセスできる。
それによりDBのパフォーマンスを向上する。

### 3.ハードウェアのサイジング
システムで利用するデータサイズを見積もり、それに十分な**ストレージを選定**する。
またシステムが十分な性能を発揮できるだけのスペックを持つCPUやメモリを持ったサーバを選定する。

### 4.ストレージの冗長構成決定
ストレージはDBのデータを保持する媒体。
RAIDを用い、可能な限り高い**耐障害性を持つようにシステムを設計**する。

### 5.ファイルの物理配置決定
DBのファイルを**どのディスクに配置するか**決める。
ある程度はDBMSが自動で配置する。

# 参考文献
この記事は以下の情報を参考にして執筆しました。

達人に学ぶDB設計徹底指南書
M1macでMonterey12.1 から12.3 にアップデートできなかった時の対処法

## 問題
m1macでMonterey12.1 から　12.3 にアップデートできなかった。

## やったこと
OSの再起動をして再度アップデート

App Stpreからmacosを検索して、そこからアップデートする

以上を試してもダメでした。

## 結論
私の環境の場合、リカバリーモードでOSをアップデートできました。
（以下を行う際にマックのデータは消えないですが、一応データを保存した方が良いです。）

- マックをシャットダウン

- 電源を長押しして再起動する。optionでOS 再インストールを押す

これで新しいバージョンにアップデートできた。
Homebrewは手で直せる ファイラーRangerの濁点問題の修正

この記事の環境はMacOS Montereyです。

Homebrewにある[Ranger](https://formulae.brew.sh/formula/ranger#default "Ranger")というファイラーのソフトを使っていた時、
濁点が正しく表示されない、修正できないという問題がありました。

![ranger_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/939698/9a527d3e-ddd9-ccec-21f2-58dc1a42c928.png)
名称未設定フォル「タ」になってる…

調べた所、MacではUTF-8にはNFD(Normalization Form Canonical Decompression)
というのが一部で使われていて、それを使用するプログラム（この場合だとpython3）を留意無く使用すると
このように濁点、半濁点が抜けたり、別で（コンヒ゜ュータみいたいに）表示されたりするそうです。

https://rcmdnk.com/blog/2019/11/19/computer-mac-screen/

（そのすぐ上の「できる韓国語…」がちゃんと表示されているのは、どうも作成された環境によって濁点の処理がされる時とされない時があるらしい）

さらに、rangerのGithubを調べた所、この問題は既知の問題だったらしく、
すでに修正パッチがありました。

https://github.com/ranger/ranger/pull/2030

ただし、この問題は大変悲しいことにマージされなかったようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/939698/b5693b81-6e9e-fe20-1df9-8b8ab112597c.png)

描いてある感じ、「python2.7とかでも動くのかい」「他でもエラーが出ないのかい」
「それらを確認しないとマージできないよ」という感じで、多分それらを検証できなかったようです。
おそらくこのレビュアーは日本の環境を用意できなかったため、自分では検証できなかったのでしょう。
そりゃそうですよね。日本でも「A」とウムラウトつきの「Ä」に違いがどうあるかはよくわかりません。
まあ直したほうがいいかもしれないが、この修正で他の言語全てで問題が起きるかわからない。
じゃあもうマージしないでおくか、と思ったか放置されたかされたようです。

さて困った。方法は２つ。
①このブランチをプルしてこれをmake？する
②手で修正してこれをmake?する

①はできれば避けたかった。この修正は２年前のものだし、それから先にやってある新しい修正を潰すことになる。

②ですが、果たしてmakeできるかどうかもわからない。そもそもHomebrewがどうやって動いているのかわかっていませんでした。

困ってhomebrewの説明を見ていたら、このような記述が。
https://brew.sh/index_ja

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/939698/e871fe05-fd33-5b55-a0e1-3c8973876364.png)

Homebrewは、ただ/usr/localのCellarというところに置いてあるだけだから、
それを改変すればのかな？ということがわかりました。
RangerはPython3で書いているということがわかりました。
Python3なら普通コンパイルしませんね。

この修正の変更を見ても、pythonで書いてあることがわかりました。
https://github.com/ranger/ranger/pull/2030/files

では手作業で直してみるか…
/usr/local/Cellar/ranger を開くと、たしかにそのままファイル群があります。

書かれているとおりに手で直してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/939698/2e36f1ae-03db-429c-8436-c584556b34e3.png)


これで直るのだろうか…
おっかなびっくりrangerを立ち上げてみます。

![ranger_05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/939698/5d8912b2-1f90-42a3-c2e8-a817a5fb26fc.png)

直ってる〜！！！

すべてのHomebrewが手で直せるかどうかはわかりませんが、
意外と手で直せるって事を知りました。
GithubからpullしたNuxtプロジェクトを、GithubレポジトリとSourcetreeで連携する方法。


1. まず、Githubから複製したいプロジェクトをダウンロードする。
2. Zipを展開する



```
npm install --save nuxt
```

[参考記事](https://www.lisz-works.com/entry/nuxt-project-first-step)


## Githubにて。
新しいレポジトリを作る。
作成されたレポジトリのhttpsアクセスURLをコピーする。

## Sourcetreeにて。
zipファイル展開したローカルディレクトリを、Sourcetreeの新規ローカル追加から、追加する。

設定項目にて。
[設定]を選び、[リモート]の[追加]で、先程のhttpsURLをパスに指定する。
その後接続。
(アプリケーション名).exe.config が効かない事例への対処→管理者権限で保存する

# 背景

とあるアプリケーションの表示言語を切り替える際に(アプリケーション名).exe.configファイルを変更する必要があったが、内容を変更したはずなのに変更がアプリケーションに反映されなかった。

半日くらいハマったので備忘録を残す。

# 結論
エディタの機能により(?)ファイルを変更できたように見えて、実際は変更できていなかった。

管理者権限でエディタを開いてファイルを変更・保存するとよい。VSCodeだと保存時に管理者権限を要求するので確実。

# 詳細

(環境)
* Windows 10
* TeraPad


(アプリケーション名).exe.configがProgram Files以下に配置されており、変更には管理者権限が必要だった。

タスクバーからエディタ(TeraPad)を起動してファイルをドラッグアンドドロップして開いていたが、この開き方だと管理者権限がなく、うまく保存ができなかった模様。
4
同エディタでファイルを開きなおすと変更内容が反映されているように見えた点がハマりポイント。

エディタをVSCodeに変えたところ、保存時に管理者権限を要求され、正常に保存でき、無事アプリケーションの言語設定に反映された。
ArduinoUNOとI2Cを使い0x40(8ビット表記0x80)に「hello...」と出力する。(Arduino)



目的
I2Cのテスト
I2C->USART9600bps->USBのテスト


![o_con267.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/4bebfde9-d716-8a2c-1eb7-b32179c31033.jpeg)






STM32G031とVSCode+STM32CubeでI2Cスレーブの受信文字をシリアル出力(受信)(STM32-I2C-USART)(CH340N)




https://qiita.com/caa45040/items/5032e6905c9425f41495





```c++




//I2C_HELLO_UNO_1

#include <Arduino.h>
#include <Wire.h>

#define en     13     // 1pin

#define ADDR1  0x40


//文字の表示 nana_seg
int ns_putc(char str1)
{

  //I2Cに送信
  Wire.beginTransmission(ADDR1);
  Wire.write( str1 );
  Wire.endTransmission();

  delay(1);//連続送信防止の為に1ms待つ

  //戻り値
  return (0);

}//ns_putc


//文字列の表示 nana_seg
int ns_printf(char *str1)
{

  //文字の中身がゼロか
  while (*str1) {

    ns_putc( *str1 ++  );

  } //while

  //戻り値
  return (0);

}//ns_printf


//初期化
void setup() {

  //GPIOの初期化
  pinMode(en, OUTPUT);

  //i2cの初期化
  Wire.begin(); //UNO

}//setup


//メインループ
void loop() {

  digitalWrite(en, 1); //LED ON debug

  //I2Cに文字列を出力
  ns_printf("hello world\r\n");

  delay(500);//0.5秒待つ


  digitalWrite(en, 0); //LED OFF debug
  delay(500);//0.5秒待つ

}//loop



```



コメントなしバージョン


```c++


#include <Arduino.h>
#include <Wire.h>

int ns_putc(char str1){
  Wire.beginTransmission(0x40);
  Wire.write(str1);
  Wire.endTransmission();
  delay(1);
  return (0);
}

int ns_printf(char *str1){
  while (*str1){ns_putc(*str1 ++);}
  return (0);
}

void setup(){
  Wire.begin();
}

void loop(){
  ns_printf("hello world\r\n");
  delay(1000);
}




```
あると嬉しいalias集

ターミナル操作で仕事することが多い人もそうでない人も。

## エイリアスとは

ファイルシステムにおけるエイリアスとは
自分で定義したショートカットのようなものです。

例えばWebの焼き鳥案件のドキュメントルートに移動する時は

```bash
#ホームディレクトリにいる場合
cd /project/yakitori-web/develop/htdocs/
```

とか

```bash
#別の遠いディレクトリにいる場合
cd ../../project/yakitori-web/develop/htdocs/
```
みたいにいちいち上から移動するのを

```bash
cdyakitori
```

みたいな感じで一発移動出来るようにする、みたいな感じ。

アレどうやるんだっけみたいなのもaliasに登録しといたら楽。


### 作り方

やってみたいけどvimの使い方が分からない人は普通のエディタで記述後コピペするのがいいでしょう
vi , o , ペースト , esc の順で叩けば大丈夫です

```bash
# bash_profileを開く
vi ~/.bash_profile

#（oを押すと行が追加されて編集モードになるので↓をペースト）
alias yakitori="やりたいこと"
#（escを押してプレビューモードに切り替え）
# 保存して閉じる
:wq

#設定を再読み込みするコマンド
source ~/.bash_profile

#定義したコマンドを打ってみる
yakitori

やりたいこと
# が実行される
```

### オススメしたい設定

```bash
# 実行位置配下に散らばる .DS_Storeをまとめて削除する
alias rmds='find . -name ".DS_Store" -print -exec rm {} ";"'

# vpnを右上のやつからポチポチして接続しないでよくなる
# ただしL2TP over IPSec方式の場合はsecretをオプションにつけないと繋がらなかった..
alias vpnstart="scutil --nc start myvpn --secret XXXXXXX"
alias vpnstop="scutil --nc stop myvpn"

# ssh接続もコマンド面倒なので全部ブチ込んでいる
alias sshniku="ssh -i ~/.ssh/niku-ec2.pem ec2-user@niku.mydev.jp"
alias sshsakana="ssh -i ~/.ssh/sakana-ec2.pem ec2-user@sakana.mydev.jp"

# 律儀にdocker-composeって打たなくてもよくなる
# dc ps とか dc up -dとかで通るようになる
alias dc="docker-compose"

```

sshとかはbash関数を定義することで引数付きのエイリアスみたいな感じで使えるようですが
（例えば基本だけ定義しといて秘密鍵、ユーザ、ホストは \\$1, \\$2, \\$3みたいにしておくとか）
~~面倒なので割愛~~ 
是非調べてみてはいかがでしょうか。

注意点として
+ 当然ながら予約済のコマンドに被せてはいけない（やったことないけど上書きされるのかな）
+ あんまり短すぎるとタイポした時に意図せぬコマンドが流れてしまうことを理解しておく
+ 結局エイリアスを覚えておかないと使えない

dcはcdと間違えそうではあるけどdocker-composeは間違えたところで何も起きないのでセーフとしている。

**おわり。**
find_or_initialize_byとfind_or_create_byについて

## 2つのメソッドの違い
Railsを勉強していく中でこの2つのメソッドに遭遇したのでそれのアウトプットをしていこうと思います。

結論からいうと、**新規作成した後保存するかしないか**が違いです。

| メソッド名 | 挙動 |
|:-:|:-:|
| find_or_initialize_by  | 新規作成した後保存しない  |
| find_or_create_by | 新規作成した後保存する  |

恐らく使い道は、送信フォームで戻るボタンを実装する際に使われたりするのかなとおもいます。

【参考文献】

https://qiita.com/taimuzu/items/0a21738d018f475d63ae
Visual Studio Codeでjupyter notebookのipynbファイルを開く

# VS codeが一番楽
ipynbファイルを開く方法はいくつかある．
- ブラウザ（ターミナルからjupyter notebook or jupyterlabを起動）
- [JupyterLab Desktop](https://github.com/jupyterlab/jupyterlab-desktop)
- Visual Studio code（拡張機能を使用）

ターミナルから起動する方法は起動時のカレントディレクトリがjupyterのルートになって，それより上の階層にjupyter内では移動できず，別のipynbファイルを開くには別のサーバーを立ち上げる必要があって面倒．

JupyterLab Desktopは独立したアプリになっているので，ターミナルからサーバー起動する面倒は無いが，ipynbファイルをダブルクリックで直接開くようなことはできない．ipynbファイルをJupyterLab Desktopで開く設定にしておけばダブルクリックで起動はできるが，ファイルはオープンされず，アプリ内でポチポチとディレクトリを辿る必要がある．

VS codeはipynbをポチれば簡単に起動できるし，そこそこ起動も早い．2021年のPython拡張機能ができてから設定も楽になった．

以下，Macに関するメモ．



# Pythonの事前準備
VS codeではPython kernelは好きなのを使えるので，HomebrewからPythonを入れておく．
jupyterが必要なのでpipでインストールしておく．

``` zsh
$ pip3 install jupyter
```


# VS codeのインストール

インストールは公式からダウンロードしてくるだけ．zipファイルを展開してアプリケーションフォルダに突っ込んでおけば良い．


## 設定

初回起動時に日本語化するか聞いてくるのでやっておく．（再起動される）

起動したら左の方にある拡張機能のアイコンをクリック．
Pythonで検索して，おそらく一番上に出てくる拡張機能を入れる．
中身はこれ
https://marketplace.visualstudio.com/items?itemName=ms-python.python
これをインストールすれば，Pylanceやjupyterなどの必要な拡張機能も色々インストールされる．

多分これだけでjupyterの設定は終わり．

ipynbファイル開いた時にどのカーネルを使うか聞いてくるで，Homebrewで入れたPythonとかを選べば良い．

VS code上でファイルを新規作成するときに，ファイル名の拡張子を.ipynbにすれば，jupyter用のファイルが作成される．

===== 2023/10/26 追記
2023年の途中で上記のPython拡張を入れてもjupyterは自動でインストールされなくなったらしい．jupyterの拡張も手動で入れておく．


## 便利な拡張機能
- [indent-rainbow](https://marketplace.visualstudio.com/items?itemName=oderwat.indent-rainbow) インデントを色分けしてくれる
- [Path Intellisense](https://marketplace.visualstudio.com/items?itemName=christian-kohler.path-intellisense) ファイル名などのpath補完
- [Python Indent](https://marketplace.visualstudio.com/items?itemName=KevinRose.vsc-python-indent) 綺麗にインデントしてくれる
- [Trailing Spaces](https://marketplace.visualstudio.com/items?itemName=shardulm94.trailing-spaces) 余分な空白を可視化してくれる


# サクッとipynbファイルを開く設定
ipynbファイルを常にVS codeで開くように設定しておく．ipynbを右クリックして
`情報を見る` --> `このアプリケーションで開く:`で`Visual Studio Code.app`を選ぶ．`すべてを変更`をクリックすると今後ipynbファイルはVS codeで開くようになる．これでダブルクリックするだけでipynbファイルを開くことができる．

## ターミナルから開く場合

ターミナルから開く場合は上記のVScodeで開く設定をしておけばopenコマンドで良い

``` zsh
$ open hoge.ipynb
```

`.zshrc`などに下記のエイリアス設定をしておけばopenコマンドも省略して直接実行でVS codeを開くことが可能．

``` zsh: .zshrc
alias -s ipynb=open
```

``` zsh
./hoge.ipynb
```

### codeコマンドをインストールする
codeコマンドをインストールすると，ターミナルから`code xxx` のように打つだけでファイルやディレクトリをVScodeで開くことができる．

インストールは，VScodeを起動して，`Command + Shift + p`と打って，codeで絞り込み，`シェルコマンド: path内にcodeコマンドをインストールします`を選択するだけ．

/usr/local/bin/code にインストールされて，中身はbashのスクリプトだった．
xcode LaunchScreenが表示されないとき。時間指定

解決のためにやったこと

①素材をAssets以外に置く
②書き出しサイズを小さくした

上記二つで解決しました！


あまりにも内容がすぐ終わったので。。。
LauchScreenの表示時間の変更は

**AppDelegate**のところで、以下のように**sleep(時間)**を書いてあげると指定できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569820/8666c9e4-25d9-edf7-a0d4-9970e87e3e1a.png)x
UNET 1.0.8: 「ビルド済みアプリ」と「Unity Editor上でのアプリ」での疎通で失敗する場合は1.1.1に


ビルド済みアプリ(クライアント)とUnity Editor上でのアプリ（サーバ）で疎通する際に、

```
IndexOutOfRangeException: NetworkReader:ReadByte out of range:NetBuf sz:0 pos:0
  at UnityEngine.Networking.NetBuffer.ReadByte () [0x0004c] in 
```

というエラーが出ました。[SyncTime](https://github.com/fuqunaga/SyncUtil/blob/master/Scripts/SyncTime.cs#L49)　という時間を同期するライブラリを使っていたのですが、そこのReadMessageでメッセージが空になっている？ためか、**メッセージのデシリアライズ処理（文字列から構造体に戻す処理）で失敗する** というのが、エラーの内容でした。

```
var msg = netMsg.ReadMessage<SyncTimeMessage>();
```


結局、 **Multiplayer HLAPI (通称UNET)のバージョンを1.0.8から1.1.1に更新することで上記のエラーが消えました**。以下は、manifest.jsonで変更した内容。

```
"com.unity.multiplayer-hlapi": "1.1.1",
```

また、ややこしいですが、Multiplayer HLAPIはなぜかキャッシュがのこってしまっていて、1.1.1から1.0.8に戻すとエラーが起こらないので、Libraryフォルダのライブラリキャッシュを消す必要があります。


## 最後に

UNETの互換性のある[Mirror](https://mirror-networking.com/) に移行するのが主流ですので、みなさん、なるべく、そっちに移行しましょう。（自分の場合はどうしても直近で必要だったので、このような対応としましたが）


Mirrorは1フレームごとに送れるバイト数が大きく、バグもUNETと比べてかなり少なく、コミュニティも大きいのでおすすめです。
Ubuntu 20.04 EC2でdocker-composeのV1をインストール


EC2でDocker-composeにハマったインストール

# 環境

OS
```bash
ubuntu:/usr/local/bin$ lsb_release -a

No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 20.04.3 LTS
Release:        20.04
Codename:       focal

```
Docker

```
$ docker -v
Docker version 20.10.9, build c2ea9bc
```


# はまりどこ

- V1.xとV2.xだとインストール方式が異なる

# 以下の記事のようなエラーが発生

インストールを実行
```sh
sudo curl -L "https://github.com/docker/compose/releases/download/2.0.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

```


[docker compose - Ubuntu 20.04でdocker-composeを公式のGithubリポジトリから正常に導入されたそうに見えるが「command not found」エラーが発生 - スタック・オーバーフロー](https://ja.stackoverflow.com/questions/85373/ubuntu-20-04%E3%81%A7docker-compose%E3%82%92%E5%85%AC%E5%BC%8F%E3%81%AEgithub%E3%83%AA%E3%83%9D%E3%82%B8%E3%83%88%E3%83%AA%E3%81%8B%E3%82%89%E6%AD%A3%E5%B8%B8%E3%81%AB%E5%B0%8E%E5%85%A5%E3%81%95%E3%82%8C%E3%81%9F%E3%81%9D%E3%81%86%E3%81%AB%E8%A6%8B%E3%81%88%E3%82%8B%E3%81%8C-command-not-found-%E3%82%A8%E3%83%A9)


# V1をインストール
v1.29をインストール

```sh
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.29.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   664  100   664    0     0   3059      0 --:--:-- --:--:-- --:--:--  3059
100 12.1M  100 12.1M    0     0  8090k      0  0:00:01  0:00:01 --:--:-- 11.8M
```

```sh
$ docker-compose -v
docker-compose version 1.29.0, build 07737305
```
[Dart]mixinとは

# mixinとは
```class```で共通する機能を、継承を使ってmixさせる。

# 具体例

## 導入
```Animal```クラスを作り、継承を使用して```Bird```と```Fish```クラスを作成する。

```dart
void main() {
  Fish().move();
  Bird().move();
}

class Animal {
  void move() {
    print('change position.');
  }
}

class Fish extends Animal {
  @override
  void move() {
    super.move();
    print('by swimming.');
  }
}

class Bird extends Animal {
  @override
  void move() {
    super.move();
    print('by flying.');
  }
}
```

一見、```Bird```と```Fish```クラスを美しく定義できているように見える。
しかし、泳ぎと飛ぶが両方できるアヒルクラスを作る際には上記の書き方では問題が出てくる。

```Bird```と```Fish```クラスのどちらを継承させるのが適切か不明となる。

```dart
class Duck extends Bird {} //Birdを継承させるべき？
class Duck extends Fish {} //Fishを継承させるべき？
```

## mixin

そこで、```mixin```の登場！！

```dart
void main() {
  Duck().swim();
  Duck().fly();
}

...

mixin CanSwim {
  void swim() {
    print('can swim.');
  }
}

mixin CanFly {
  void fly() {
    print('can fly.');
  }
}
  
class Duck with CanSwim, CanFly {
}
```

```mixin```によって共通する機能をどちらも継承することができる。

# まとめ

```mixin```で共通する機能を分離させて、```with```で継承させる。
I18n::InvalidLocaleエラーについて

今回ツイート機能の投稿日時を以下の手順で日本時間に設定したところ、
deviseの新規登録時の生年月日入力欄でエラーが発生した。

原因としてはもともとen.yml(英語)で設定されていたのにも関わらず、
ツイート時間を無理やりja設定にしてしまったのが理由でエラーが出てしまったと推測する。

ツイート時間変更時に行なった作業
①config/application.rbを以下のように設定
```config/application.rb
module TimeFormatSandbox
  class Application < Rails::Application
    # ...

    # デフォルトのロケールを日本（ja）に設定
    config.i18n.default_locale = :ja
  end
end
```
②次に表示したいhtml上を以下のようにlメソッドを使用するための設定をした
```index.html.erb
<td><%= l user.created_at %></td>
```
```config/locales/ja.yml
ja:
  time:
    formats:
      default: "%Y/%m/%d %H:%M:%S"
```
結果的にツイート投稿時間は日本時間に変更されたが、
デプロイ後にdevise新規投稿時に生年月日登録の個所でエラーが発生した。

# 解決策
(正解はわからないのですが私はこの方法でエラーが解消しました)
①新たなブランチを作成し、上で行なった作業を全て削除した。
②それでもエラーが出ていたのでエラー文を読むと「ローカルでJaは有効でありません」ということだったので
config/localesに「ja.yml」を新たに作成した。
③作成した「ja.yml」にhttps://github.com/svenfuchs/rails-i18n/blob/master/rails/locale/ja.yml　のGithubに記載されているコードを参考にさせて頂き、
ja.yml上に記述した。

この3点を行なったことでエラーが解消しデプロイも正常に成功した。
*追加でindex.html.erb上の記述を<%= tweet.created_at.strftime('%Y/%m/%d %H:%M:%S') %>にしたことでツイート日時もうまく表示することができた。

おそらく正しい方法ではないかと思いますがひとまずエラーが解消できてよかった。

もしアドバイスやご指摘等ございましたらコメントなど頂けますと幸いです。

以上
Nuxt.js とfirebaseを使ったプロジェクトの環境設定方法



以下を実行。

```terminal:terminal
$ npx create-nuxt-app <project-name>
```

[参考記事](https://www.techpit.jp/courses/60/curriculums/64/sections/518/parts/1769)


選択項目には、
SPA、Vuetifyなどを選択。

## 各モジュールのインストール

### dotenvのインストール
```
npm install --save @nuxtjs/dotenv
```


### firebaseモジュールのインストール
```
npm install firebase@8.6.8
npm install @nuxtjs/firebase@7.6.1
```
jQueryのコードをECMAScript/JavaScriptのコードに変換する

# jQueryのコードをECMAScript/JavaScriptのコードに変換する

# はじめに
以前の10年ほど前までは、JavaScriptと言えば、jQuery一択であった。
しかしこの10年で、Node.jsの登場により、Angular/React/Vue等の様々なフレームワークが活用されるようになった。
またJavaScriptの規格の一つであるECMAScriptもバージョンアップを行い、様々な機能が追加されている。
昨今ではjQueryもレガシーコードの一つとなりつつある。
そこで今回は、jQueryとECMAScript/JavaScriptのコードを変換するためのスペニットを以下に記載する。

# コードスペニット
## セレクタ

```
// jQuery
$("#name");
$(".item");

// ECMAScript/JavaScript
document.querySelector("#name");
document.getElementById("name");
document.querySelectorAll(".item");
document.getElementsByClassName("item");
```

## 表示/非表示
```
// jQuery
$("#name").show();
$(".item").hide();

// ECMAScript/JavaScript
// ID指定のみ可。クラス/タグ名の場合はループ処理を挟む必要有り
document.querySelector("#name").style.display = "block";
document.getElementById("name").style.display = "none";
```

## 非活性/活性
```
// jQuery
$("#name").prop("disabled", true);
$(".item").prop("disabled", false);

// ECMAScript/JavaScript
// ID指定のみ可。クラス/タグ名の場合はループ処理を挟む必要有り
document.querySelector("#name").disabled = true;
document.getElementById('name').disabled = false;
```

## ループ処理
```
// jQuery
$(".item").each((index, element) => {
    ...
});

// ECMAScript/JavaScript
document.querySelectorAll('.item').forEach((element, index) => {
    ...
});
```
# リンク
* [jQuery不要論について考える](https://www.deep-rain.com/programming/javascript/658#jQuery-2)
* [JavaScript 要素を表示/非表示にするサンプル(displayとvisibility)](https://itsakura.com/javascript-display)
* [【JavaScript】一旦初心に戻ってDOM操作を学び直す](https://qiita.com/irico/items/18471dd3260f1297cabb)
Stimulusを使ってドラッグ&ドロップでファイルアップロード

Rails で input[type=file] の入力欄にファイルをドラッグ&ドロップして選択する機能を追加しようとネットを調べてみたのですが、script 要素にべた書きの実装例しか見つからなかったので、Stimulus を使った実装をしてみました。

# 環境

+ Ruby 3.1.1
+ Ruby on Rails 7.0.2

# View

既存のページには、data-controller 属性と data-action 属性と data-*-target 属性を追加するだけなので、ほとんど手を入れずに済みます。

Stimulus 側に file_drop という名前のコントローラを作るので、data-*-target 属性の値や名前もそれに合わせて data-file-drop-target とします。

```erb:app/views/users/_form.html.erb
  ...
  <div data-controller="file-drop"
      data-action="dragover->file-drop#dragover dragleave->file-drop#dragleave drop->file-drop#drop">
    <%= form.label :image, style: "display: block" %>
    <%= form.file_field :image, 'data-file-drop-target': 'fileUpload' %>
  </div>
  ...
```

# Controller

file_drop_controller.js 中の `targets` で指定した値(`fileUpload`)から自動的に `fileUploadTarget` というプロパティが生成されます。
これは自動で生成されるため、targets の値に `file-upload` のようなケバブケースは使えません。
`'data-file-drop-target': 'file-upload'` って書きたかったのですが諦めました。

data-action 属性でイベントとそれに対応するコントローラ#メソッドを指定したものが、ここで呼ばれます。

script 要素にべた書きだと `element.addEventListener('dragover', () => {})` としていたところを、ちょっとだけわかりやすく書けるようになります。

```js:app/javascript/controllers/file_drop_controller.js
import { Controller } from '@hotwired/stimulus'

export default class extends Controller {
  static targets = ['fileUpload']

  dragover(e) {
    e.preventDefault()

    // dragover したときに border の色を変える
    this.fileUploadTarget.classList.add('border-primary')
  }

  dragleave(e) {
    e.preventDefault()
    this.fileUploadTarget.classList.remove('border-primary')
  }

  drop(e) {
    e.preventDefault()
    this.fileUploadTarget.classList.remove('border-primary')

    const files = e.dataTransfer.files
    if (typeof files[0] !== 'undefined') {
      this.fileUploadTarget.files = files
    }
  }
}
```

あとは作成したコントローラを読み込むだけ。

```js:app/javascript/controllers/index.js
import { application } from './application'

import FileDropController from './file_drop_controller'
application.register('file-drop', FileDropController)
```
オートレイアウトに関するメモ RegularCompact対応など

StoryBoardで辛いことが多々ある。


レイアウト制御関連が本当に途方も無い。
色々な制約を与えることができる。
その制約に絡め取られて身動きが取れなくなることも多い。




WidthRegular時のみに制約をかけることもできる。
類似性のある制約を２つ同時に存在させ、優先度を微調整することもできる。



上記の組み合わせだけでも、あとから見返したときに、「スパゲッティ状態」に陥るだろうなと思える。


しかし、これはあくまでメモであって、解法ではない。