OmniAICreator/Qiita-1.07M huggingface dataset:
before_actionで同じコードをメソッドにまとめる方法

before_actionとは使用すると、コントローラで定義されたアクションが実行される前に、
共通の処理を行うことができるメソッド

<b>修正前</b>

```ruby
  def show
    @item = Item.find(params[:id])
  end

  def edit
    @item = Item.find(params[:id])
    unless @item.user_id == current_user.id
      redirect_to action: :index
    end
  end

  def update
    @item = Item.find(params[:id])
    if @item.update(item_params)
      redirect_to item_path
    else
      render :edit
    end
  end
```

showアクション、editアクション、updateアクションに同じ@item = Item.find(params[:id])が
連続して記述してある
また、editアクションにあるunless @item.user_id == current_user.idをアプリの安全性を高めるため、updateアクションでも使えるようにしたい

<b>修正後</b>


```ruby
  before_action :set_item, only: [:edit, :update, :show]
  before_action :move_to_index, only: [:edit, :update]

  def show
  end

  def edit
  end

  def update
    if @item.update(item_params)
      redirect_to item_path
    else
      render :edit
    end
  end

  private 

  def set_item
    @item = Item.find(params[:id])
  end

  def move_to_index
    unless @item.user_id == current_user.id
      redirect_to action: :index
    end
```
before_action :set_item, only:[:edit, :update, :show]と記述することでeditアクションと
updateアクションとshowアクションとが実行される前に、set_itemに定義されている処理が実行される
set_itemはプライベートメソッド内に記述
またunless @item.user_id == current_user.idも同じようにbefore_actionで記述して
プライベートメソッド内でmove_to_indexと定義することでeditアクション、updateアクションで使用できる
【Rails】ActiveStorageによる画像アップロード

# はじめに
　現在勉強の一環で作成中の音楽レビューアプリでActiveStorageによる画像アップロードを使用したのでメモ。
  
# アプリについて
・作成中のアプリは音楽アルバムのレビューアプリ。
・ActiveStorageを利用し、Recordモデルに画像を `:jacket` として 紐づける。

#ActiveStorageのインストール
以下のコマンドでインストールする。

```
   rails active_storage:install
```
  

#Recordモデルを編集
次にRecordモデル編集し、一つの画像を持つようにする。
今回はアルバムのジャケットとして `:jacket` とする。

```ruby:app/models/record.rb
class Record < ApplicationRecord
  has_one_attached :jacket

　#以下省略
end

```
　　
そして`db:migrate`する。

#Recordにジャケットを紐づける
次にRecord新規作成（編集）のページにファイルアップロードをするタグを追加。

```erb:app/views/records/_form.html.erb
<%= form_with(model: @record, local: true) do |f| %>
 <div class="form-group">
    <%= f.label :jacket %>
    <%= f.file_field :jacket %>
  </div>

  <%# 省略 %>

  <%= f.submit "Create Record", class: "btn btn-info" %>
<% end %>
```
  
　　
次はフォームを正しく受け取れるように `records_controller`のストロングパラメータに `:jacket` を追加する。

```ruby:app/controller/records_controller.rb
class RecordsController < ApplicationController

  #省略

  private

    def record_params
      params.require(:record).permit(:name, :artist, :release_year, :genre_id, :jacket)
    end
end
```

  
#ビューで表示
ビューでは`<%= image_tag record.jacket %>`のように書くことで画像を表示できるが、このままだとアップロードされた画像サイズがバラバラなのでリサイズできるようにする。
### mini_magickのインストール
まずはGemfileにMiniMagickを追加。

```:Gemfile
    gem 'mini_magick'
```
そして`bundle install`する。
　　
##実際に表示する
先ほどMiniMagickを追加したことにより、
`<%= image_tag record.jacket.variant(resize:'120x120') %>`
のようにして画像をリサイズして表示できる。

```erb:app/views/records/index.html.erb
<% @records.each do |record| %>
      <div class="album text-center">
        <%= link_to record do %>
        <div class="mb-2">
　　　　　　<%# ここに表示 %>
          <%= image_tag record.jacket.variant(resize:'120x120') %>
        </div>
        <h5 class="mb-0 font-italic"><%= record.name %></h5>
        <% end %>
        <small><%= link_to record.genre.name, records_path(genre: record.genre.name) %></small>
        <p class="text-bold"><%= record.artist %></p>
      </div>
<% end %>
```
これで画像が表示される。

#N+1問題
これまでで画像の表示は完了したがN+1問題が発生していたので修正する。

Records/index ページで一覧を表示する時に、`:jacket`画像を読み込むためRecordの数だけDBに問い合わせているのが問題。

これを解決するためには`records_controller`を編集する。

```ruby:app/controller/records_controller.rb
class RecordsController < ApplicationController

  def index
    #省略
　　@records = Record.all.includes(jacket_attachment: :blob)
    #省略
  end

end

```
`Record.all`と書いていたところを、
`Record.all.includes(jacket_attachment: :blob)`
とすることで解決した。
RDSでMySQLからAuroraに移行しようとしてハマった

RDSでMySQL5.6のエンジンが非対応になるとのことで、この際Auroraに変えるか、と思ったら、ちょっとハマったので備忘録として残します。

MySQLからAurora MySQLへの移行方法は、以下の公式ブログにベストプラクティスが記載されています。

https://aws.amazon.com/jp/blogs/news/best-practices-for-migrating-rds-for-mysql-databases-to-amazon-aurora/


簡単に手順を説明すると

1. MySQLインスタンスからAuroraリードレプリカを作成
1. インスタンスが立ち上がったら、ステータスを確認して、レプリケーションできてる事を確認
1. （書いてないけど）WebアプリケーションのDBの向き先をAuroraに変更
1. MySQL側のインスタンスを停止

親切に画面のスクリーンショットまで載っており、途中までは問題も起きずに進められたのですが、 **レプリケーションのMasterとなっているMySQL側のインスタンスを停止ができなくて**詰まりました。
アクションから停止を選択し、進めていくと、

"Cannot stop or start a Read-Replica instance"

というメッセージが出て、停止できない。

「いや、これリードレプリカじゃなくてMasterなんだが？　Masterを停止したらリードレプリカが昇格するんちゃうんか？　話がちゃうで」

という疑問もありましたが、とにかく、レプリケーションの解除を行う必要がありそうです。

色々情報を彷徨ったのですが、ようやく見つけた方法が**レプリカ側を昇格させる**という方法。

RDSインスタンスの一覧から、リードレプリカとなっているのAurora **クラスタ** を選択し、アクションから **昇格** を選択する。

昇格自体は10秒程度で完了したと思います。恐らくダウンタイムも発生していないと思われます。多分...

昇格が完了後、無事MySQLインスタンスは停止できましたとさ。

めでたしめでたし。


### 追記

ほかの方法を記載している記事を発見しました。

https://nulab.com/ja/blog/nulab/migrate-to-aurora/

上記の記事では、MySQLクライアントからコマンドをコールする事でレプリケーションを解除しています。
私は昇格によって解除したので、現在でもコマンドでの解除が有効かどうかは検証していません。

下記は上記記事からの引用です。

```
mysql> call mysql.rds_reset_external_master;
+----------------------+
| message              |
+----------------------+
| Slave has been reset |
+----------------------+
1 row in set (0.01 sec)
Query OK, 0 rows affected (0.01 sec)
```
【簡単】WindowsにLinuxを入れてみた【結論：WSL2をインストールすればOK】

## 背景
* 転職先でWindowsPCを使用し始めてからずっとLinuxを使いたいと思っていました
* 簡単な方法はないかなと色々と探していたところ、WSL2を入れれば良いことが分かったので、試してみました

## WSL 2とは何か？
仮想マシンを使い、Linuxカーネルが動作する「本物のLinux環境」

## WSL2のインストール方法

### Windowsの機能の有効化
* コントロールパネル＞プログラムと機能>Windowsの機能の有効化または無効化、を選択
* 『Linux用Windowsサブシステム』と『仮想マシン プラットフォーム』にチェックを入れて、OK
![3e91fc324bbcc89a6257c843cd4fe2af.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/882682/f0aed989-1d3d-d952-d2ea-ee1c2a58a56c.png)
* PC再起動する

### 規定のバージョンをWSL 2に変更
* Poweshellで以下コマンドを実行

```Powershell
PS　>wsl --set-default-version 2
```
※カーネルコンポーネントの更新を要求される場合は、以下から更新パッケージをダウンロードして実行する
* https://docs.microsoft.com/ja-jp/windows/wsl/install-win10#step-4---download-the-linux-kernel-update-package

### Microsoft StoreからLinuxをインストール
* スタートメニューからMicrosoftストアを開き、右上の検索マークから「Linux」と検索する
* 使用したいディストリビューションを選択し、「入手」をクリック
* そのまま進んで、再度に起動ボタンが表示されるので、クリック

### 初回設定
以下の画面が表示されるので、数分待つ
その後、ユーザ名とパスワードの入力が求められる(PCのログイン情報と合わせる必要はなし)
![8e675962088205f95c3deb158ba78a97.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/882682/50f80e65-f502-1640-67df-a6774332b262.png)

### 動作確認
* Poweshellで以下を実行し、以下のように表示されることを確認する

```Powershell
PS C:\Users\username> wsl -l -v 
NAME STATE VERSION 
* Ubuntu Stopped 2
```

* この際に、Versionが1になっていれば、以下を実行する。

```Powershell
PS　>wsl --set-version <Distribution> 2
```
`<Distribution>` ：上記コマンド`wsl -l -v`の結果列`NAME`の値を記載

最終的に以下のように表示されればOK

```Powershell
変換中です。この処理には数分かかることがあります... 
WSL 2 との主な違いについては、https://aka.ms/wsl2 を参照してください 
変換が完了しました。
```

### 起動方法
スタートメニューから「wsl」と検索する

### 参考
https://www.pc-koubou.jp/magazine/40465
cebe/markdownで改行が<br>に変換されないのに対処する

##対処したい問題
phpのシステムにマークダウンパーサを組み込むにあたり、[cebe/markdown](https://github.com/cebe/markdown)は有力な選択肢のひとつです。
しかし普通にパースしただけでは改行コードが\<br>に変換されないため、こちらの期待する見た目になってくれません。一応、スペースを連続で２つ挿入すると\<br>コードに変換されるため改行は実現できるのですが、直感に反した挙動でありユーザフレンドリーとは言えません。
そこでこの記事では、cebe/markdownにおいて改行コードを\<br>に変換させる方法を記します。

※公式ドキュメントを読めば記述があるのですが、日本語での情報が見当たらなかったためこのような記事にしました

![スクリーンショット 2021-04-13 20.15.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138421/b713daf9-ff35-8ac2-841c-22495f38f813.png)
例）期待に反する見た目。本文が適切に改行されていない

##対処方法
結論となるコードを先に示します。

```sample.php
$parser = new GithubMarkdown(); // パーサを生成
$parser->enableNewlines = true; // 改行コードを<br>に変換する設定を有効に
$parsedText = $parser->parse($markdownText); // パースを実施
```

![スクリーンショット 2021-04-13 20.14.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138421/026a437c-fde7-23af-1bf5-53d6c5ec9e52.png)
例）期待した通りの見た目。本文が適切に改行されている

まず「改行コードを\<br>に変換する」を実現するためには(cebe/markdownには他の選択肢もありますが)GithubMarkdownである必要があります。
パーサのインスタンスを生成後、`$parser->enableNewlines = true;`とすることで改行を\<br>に変換する設定を有効にします。
あとは通常とおりにパースを実施するだけです。

##参考
https://github.com/cebe/markdow
【AWS】無料でできること

#プログラミング勉強日記
2021年4月13日

#AWSの無料で使えるサービスの種類
　AWSの無料で使えるサービス内容によって3種類ある。前3種類のAWS無料枠のサービスは期間や利用できるサービスが異なる。

- 常に無料
- 12か月間無料
- トライアル

##常に無料の枠
　この枠では、該当するサービスが永遠無料でできる。AWSを使っているすべてのユーザが利用できる。

##12ヶ月無料の枠
　AWSにサインアップした時点から12か月間無料でできるサービス。

##トライアルの枠
　該当するサービスを一定の期間無料で利用することができる。サービスによって無料で利用できる条件が異なるので、注意が必要。(条件は回数の場合もあれば機関の場合もある。)

#無料でできること

##常に無料の枠
　アプリ利用時の設定が不要で、大量のデータ管理、高速のデータ処理を行える。

##12ヶ月無料の枠
　利用設定の手間がかかることなく、データの取得・保存が簡単にでき、様々な管理を自動化できる。
　<b>1年間全てのサービスが無料というわけではない！</b>AWSのアカウント登録から1年間有効な無料枠があるというサービスなので、無料で使えるのは一部に限る。なので、該当しないサービスの利用では課金されるので注意が必要。

##トライアルの枠
　作業効率を上げることができ、安全な環境で作業をできる。



#参考文献
[AWS 無料利用枠](https://aws.amazon.com/jp/free/?all-free-tier.sort-by=item.additionalFields.SortRank&all-free-tier.sort-order=asc)
[もう悩まない！AWSの無料利用枠でできることをわかりやすく解説](https://www.sejuku.net/blog/132236)
ループ外でカスタムフィールドの値を取得する

カスタムフィールド（Select）の内容で動的に検索ボックスを生成する場合など。


# フィールドタイプ Select の場合
```php
/**
 * Selectタイプのカスタムフィールドから、選択肢を取得する
 * @see    https://www.rcnt.jp/blog/advanced-custom-fields/
 * @param  string $lavel ラベル
 * @return array 二次元配列。【red : 赤】形式で登録している場合、キーは red になる
 */
public function get_acf_select_choices(string $lavel): array
{
    $post         = get_page_by_title($lavel, 'OBJECT', 'acf-field');
    $post_content = $post->post_content;
    $unserialize  = maybe_unserialize($post_content);
    $select       = $unserialize['choices'];

    return $select;
}
```
[PHP] メモリの上限を無制限にする

#概要

```
Fatal error: Allowed memory size of 1610612736 bytes exhausted...
```

composerでパッケージをインストールする際に上記のエラーが発生することがあります。

#原因
このエラーはパッケージがメモリの制限を超えてしまっていることで起きるエラーなので、
php.iniからメモリの制限を開放することでエラーを回避することができます。

#方法

* php.iniファイルを開く
* 下記を追加

```php.ini
memory_limit = -1
```
【Python】pandasというライブラリを使ってCSVファイルを読み込み、円グラフを作成する。

pythonを使用してExcelファイルの操作を勉強しています。
本日の気づき(復習)は、CSVの読み込みとグラフ作成に関しての続きです。
pythonでExcelを操作するため、openpyxlというパッケージを使用しています。

```csvs:売上.csv
部門,１月,２月,３月
商品A,600,700,800
商品B,4100,3800,4500
商品C,2900,1800,3000
商品D,800,900,1000
商品E,600,550,720
```

前回同様、上記のようなCSVファイルを読み込み

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/927441/c468ffef-7ccc-5e5c-fd64-bd9dc1e8f338.png)

この様な円グラフを作り貼り付けたいです。

# PieChartオブジェクト
円グラフ作成にはPieChartオブジェクトを使用します。
グラフの作成方法自体は棒グラフと同じですが

気を付けるポイントが２点あります。

- 円グラフに表示する順番
- 各データの割合表示

どちらも円グラフを作成する場合は大事なポイントだと思います。

### 円グラフに表示する順番

```python
DataFrame.sort_values(by='ソートする項目', ascending=昇順は「True」,降順は「False」)
```
円グラフでデータを確認する場合は
占める割合の大きいものから順に表示したいので
CSVデータを張り付ける前にデータをソートしてしまいたいです。
そこで、上記のDataFrame.sort_valuesメソッドを使ってソートします。

### 各データの割合表示

```python
pie.dataLabels = DataLabelList()
pie.dataLabels.showPercent = True
```

円グラフはデフォルトでは割合表示がされていないみたいです。
表示するためには、PieChartオブジェクトの
DataLabelList.showPercent属性をTrueにします。

# 最終的なコード

```python
import pandas as pd
from openpyxl import Workbook
from openpyxl.chart import PieChart, Reference
from openpyxl.chart.label import DataLabelList
from openpyxl.utils.dataframe import dataframe_to_rows

wb = Workbook()
ws = wb.active

# CSVファイル読込み
df = pd.read_csv('売上.csv', encoding='utf-8')

# データを降順でソート
df = df.sort_values(by='１月', ascending=False)
for row in dataframe_to_rows(df, index=None, header=True):
    # データを１行ずつ追加
    ws.append(row)

# 円グラフを選択
pie = PieChart()

# 円グラフのスタイル設定
pie.style = 2

# グラフのデータ範囲を設定
data = Reference(ws, min_col=2, min_row=2, max_row=ws.max_row)

# ラベルの範囲を設定
labels = Reference(ws, min_col=1, min_row=2, max_row=ws.max_row)

# グラフにデータを追加
pie.add_data(data)

# 円グラフのラベルを追加
pie.set_categories(labels)

#割合をパーセント表示
pie.dataLabels = DataLabelList()
pie.dataLabels.showPercent = True

pie.title = '部門別売上'

# 棒グラフをシートに追加
ws.add_chart(pie, 'A9')

wb.save('部門別売上_円グラフ.xlsx')
```

何とかできました。ソートとかは使い勝手のいいメソッドなので
早めに知る事が出来て良かったです。

# おまけ pie.styleの種類

pie.styleには、
１～４８までの整数値を指定することでスタイルを変更できるのですが
一覧表みたいなものが見つけられませんでした。

ということで、上記の応用でこんなものを作りました。

```python
import pandas as pd
from openpyxl import Workbook
from openpyxl.chart import PieChart, Reference
from openpyxl.chart.label import DataLabelList
from openpyxl.utils.dataframe import dataframe_to_rows

wb = Workbook()
ws = wb.active

# CSVファイル読込み
df = pd.read_csv('売上.csv', encoding='utf-8')

# データを降順でソート
df = df.sort_values(by='１月', ascending=False)
for row in dataframe_to_rows(df, index=None, header=True):
    # データを１行ずつ追加
    ws.append(row)

for i in range(1, 49):
    pie = PieChart()
    pie.style = i
    data = Reference(ws, min_col=2, min_row=2, max_row=ws.max_row)
    labels = Reference(ws, min_col=1, min_row=2, max_row=ws.max_row)
    pie.add_data(data)
    pie.set_categories(labels)

    pie.dataLabels = DataLabelList()
    pie.dataLabels.showPercent = True
    pie.title = f'{i}'

    ws.add_chart(pie, f'A{(i-1)*16+9}')

wb.save('部門別売上_円グラフ一覧.xlsx')
```


試しに作ってみましたが、意外と面白いです。

個人的にはスタイル「10」がお気に入りです。
[Git] 過去のコミットの Author と Committer 情報を書き換える

過去のコミット履歴から、特定のコミットの Author と Committer を一気に書き換える方法です。

# 経緯

自分は仕事とプライベートで GitHub アカウントを分けています。

最近、間違った方のアカウント名・メールアドレスでコミットしてしまっていたことに後から気付いて、修正したいことがありました。

まだプロジェクトとしては序盤でしたが、他の人のコミットも少し入っていて、その中から自分のコミットだけを修正する方法を調べたので、残しておきます。

# やり方

便宜上

- プライベートの GitHub アカウントを `Neo <neo@example.com>` 
- 仕事の GitHub アカウント名を `Anderson <anderson@example.com>`

として、 `Neo <neo@example.com>`  => `Anderson <anderson@example.com>` に変更したいとします。

一応、変更前のコミットを見てみると、以下のようになっているはずです。

```zsh:修正前
% git log --pretty=full -1
commit xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx (HEAD -> branch/hoge, origin/branch/hoge)
Author: Neo <neo@example.com>
Commit: Neo <neo@example.com>
```

これを上書きします。

**※ コミット情報を上書きするので、念の為バックアップ用のブランチを切っておいた方が良いです**

```zsh
# 確認
git log --pretty=full

# 修正
git filter-branch --env-filter '
if [ $GIT_AUTHOR_NAME = "Neo" ]
then
    export GIT_AUTHOR_NAME="Anderson"
    export GIT_AUTHOR_EMAIL="anderson@example.com"
    export GIT_COMMITTER_NAME="Anderson"
    export GIT_COMMITTER_EMAIL="anderson@example.com"
fi'
```

実行後に `git log --pretty=full` してみると、該当するコミット（例では Author が Neo のコミット）だけが上書きされているはずです。

```zsh:修正後
% git log --pretty=full -1
commit xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx (HEAD -> branch/hoge, origin/branch/hoge)
Author: Anderson <anderson@example.com>
Commit: Anderson <anderson@example.com>
```

あとは、 `--force-with-lease` を付けて git push すれば OK。

# 参考

- [Git の Commit Author と Commiter を変更する \- Qiita](https://qiita.com/sea_mountain/items/d70216a5bc16a88ed932)
- [指定したCommitのAuthorとCommitterを書き換える](https://tosi-tech.net/2019/12/rewrite-git-committer-and-author/)
.gitignoreでファイルをGitの管理対象外にする方法

## .gitignoreとは
Gitの管理対象から除外するファイルやディレクトリを指定するファイル

## .gitignoreでファイルまたはディレクトリを指定する方法
.gitignoreでGitの管理対象外とするファイルまたはディレクトリを指定する場合、.gitignoreからの相対パスで指定する。

以降の説明をするにあたって、以下のようなディレクトリ構成があったとする。

```
sample_directory
 ├ directory
 │  ├ file1.txt
 │  └ file2.txt
 ├ directory2
 │  ├ directory
 │  │  └ file1.txt
 │  └ file2.txt
 └ file1.txt
```

### コメントアウト
\#から始まる行はコメントになる。

```shell:.gitignore
# コメント
```

### 特定のファイル・ディレクトリをGitの管理対象から除外する
末尾以外に「/」を含めて指定した場合、パスで指定したファイルまたはディレクトリのみをＧｉｔの管理対象外とする。

```shell:.gitignore
# 特定のファイルを管理対象外とする
/directory/file1.txt

# 特定のディレクトリを管理対象外とする
/directory
```
先頭の「/」は.gitignoreファイルと同じ階層のファイルまたはディレクトリを指す。

### 同一のファイル・ディレクトリを全てGitの管理対象から除外する
「/」を含めずに指定または、末尾にのみ「/」を含めて指定（ディレクトリのみ）した場合、.gitignore以下の全サブディレクトリ下にある同名のファイルまたはディレクトリをGitの管理対象外とする。

```shell:.gitignore
# 同名のファイルを全て管理対象外とする
file1.txt

# 同名のディレクトリを全て管理対象外とする
directory
# または
directory/
```

### ワイルドカード
任意のパターンに一致するファイル・ディレクトリを指定する。

```shell:.gitignore
# 「/」を除く全ての文字にマッチする
# 全てを管理対象外とする
*

# 特定のディレクトリ以下を全て管理対象外とする
/directory/*

# 特定の拡張子のファイルを全て管理対象外とする
*.txt
```

### 除外対象から外す（管理対象に含める）
除外対象に含まれているファイル・ディレクトリをGitの管理対象に再び含める。

```shell:.gitignore
# .gitignoreファイルと同階層にあるfile1.txtのみ管理対象とする
*
!/file1.txt
```

ただし、ディレクトリを除外したあとにディレクトリ内の一部のファイルに対して「!」を使用してもGitの管理対象に含めることはできない。

除外したディレクトリから一部のファイルのみGitの管理対象に含めたい場合、以下のようにディレクトリを除外せずにディレクトリ内部のファイル全てを除外した後、一部ファイルに対して「!」を使って管理対象に含める。

```shell:.gitignore
# ディレクトリ自体を管理対象外としたあとでは、ディレクトリ内のファイルを管理対象に戻せない。
# /directory/
# !/directory/file1.txt

# ディレクトリ内部のファイルを全て管理対象外とした後に特定のファイルを管理対象に戻す。
/directory/*
/directory/file1.txt
```

## 参考資料
Markdown: [gitignore - Specifies intentionally untracked files to ignore](https://git-scm.com/docs/gitignore)
Markdown: [【IT用語】.gitignoreの書き方を図解形式で理解しよう!](https://pikawaka.com/word/gitignore)
ROSAで作成されるAWSのリソースを調べた

こんにちは。
AWSで気軽にOpenShiftが使える[ROSA](https://aws.amazon.com/rosa/)がリリースされたはいいものの、「結構いい値段するんじゃないかな…」と思ってる方も多いかと思います。
実際にROSAを使ってみて、どういうリソースが作られてるのかを整理したので、自分の備忘を兼ねて書き残してみました。

# 目的
- ROSAのコストイメージや構成を確認したかったので、デフォルトで構築するとどういうリソースができるのかを調査しました
    - 全ては調べきれなかったので、コストに影響が大きそうなNWとEC2周りを重点的に調査してます

## 調査した環境
- rosa create cluster --cluster-name XXXX  を実行して作成した環境を調査しています
- 細かい環境の作り方はこちらを見ていただくと良いかと。（@Yusuke-Yさんありがとうございます）
    - https://qiita.com/Yusuke-Y/items/bffc2a1197ff4f7bbb3e

## 調査結果
- 作成されたEC2リソース一覧

|リソース種別               |個数               |
|:------------------------:|:-----------------:|
|EC2インスタンス(m5.xlarge) |5                  |
|EC2インスタンス(r5.xlarge) |2                  |
|EC2インスタンス(t2.micro)  |構築時のみ全region分|
|EBS                       |17                 |
|EBSSnapshot               |5                  |
|SecurityGroup             |5                  |
|NLB                       |2                  |
|CLB                       |3                  |
|TargetGroup               |3                  |

- 作成されたNWリソース一覧

| リソース種別              |個数|
|:------------------------:|:-----------------------:|
|VPC                       |1                        |
|Subnet                    |2(PublicとPrivate各1つ)  |
|RouteTable                |2                        |
|InternetGateway           |1                        |
|ElasticIP                 |1                        |
|S3Endpoint                |1                        |
|NatGateway                |1                        |
|NetworkACL                |1                        |


- 作成されたリソース一覧(その他)

|リソース種別|個数|
|:---------:|:-:|
|S3Bucket   |2  |
|HostedZone |2  |

## 気になるところ
結果としては上記の通りなのですが、調べてみて気になったところをいくつか記載します。

### EC2インスタンスが多い
xlargeクラスのインスタンスが7つ上がるので、それだけで結構コストがかかります。
会社などで使う分には大した額では無いでしょうが、個人でちょっと試してみる、という場合には中々負担が大きいです。

### LBがやたら多い
ROSAをデフォルトで入れた場合、CLBが3つ、NLBが2つ作成されます。
集約できそうな気もしますが、ROSAで作成された環境に手動で手を加えるのはサポート外になるようです。

### Bootstrap用（？）のEC2が全リージョンに作成される
環境作成時にBootstrap用と思われるEC2が全リージョンに作成されるという動きをするため、一時的に全リージョンにEC2インスタンスが作成されます。
t2.microなのでそれほどコストには響かないとは思いますが、ちょっと気持ち悪い動きをします。

### WAFが適用できない
AWSのWAFをロードバランサに適用する場合はALBへの適用となりますが、ROSAで作成されるアプリの入り口となるロードバランサはCLBになります。
そのため、WAFを適用したい場合はALBを別途作成する（ROSAでVPCを作成した場合は他のVPCへ配置）か、AWSのWAF以外を利用する必要があります。

## まとめ
正直な感想としては、個人で使う分には決して安くは無いというのが感想ですね…上記以外にOpenShiftのライセンス費用もわずかですがかかります。
具体的なコストで言うと、クラスターを立ち上げた後で8時間ぐらい起動しっぱなしにしていたところ、請求はコミコミで**10$強**でした。

とはいえ、OpenShiftの導入が格段に容易になったことから、ちょっと使ってみたい、一日ぐらい触れれば満足、というニーズにはフィットすると思います。
気になった方は是非一度お試しください。

内容に誤記等あればご指摘ください。よろしくお願いします。
WEBアプリケーションに画像をアップロードする機能を実装する方法

#WEBアプリケーションに画像をアップロードする機能を実装する方法
Javaを利用して作成したWEBアプリケーションに画像投稿機能を実装する際の手順について記載します

イメージとしては下記の図のようなイメージになります。
![Something went wrong]()


画像のアップロードにはHTMLのformタグとinputタグを利用します

```HTML:フロントエンド
<form method="post" >
  <input type="file" name="uploadImage" />
  <input type="submit" value="送信" />
</form>
```

![Something went wrong]()

バックエンド側では、Fileクラスを利用して受け取ります

```Java:バックエンド
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	// Fileクラスのインスタンス化(保存するディレクトリの指定)
	File uploadDir = new File("/Users/test/Documents/app/WebContent/images");
	// リクエストパラメーターから画像の取得
	Part fPart = request.getPart("uploadImage");
	// 画像の名前を決める
	String fName = "testphoto";
	// 保存処理の呼び出し
	save(fPart, new File(uploadDir, fName));

//保存処理
public void save(Part in, File out) throws IOException {
	BufferedInputStream br = new BufferedInputStream(in.getInputStream());
	try (BufferedOutputStream bw = new BufferedOutputStream(new FileOutputStream(out))) {
		int len = 0;
		byte[] buff = new byte[1024];
		while ((len = br.read(buff)) != -1) {
			bw.write(buff, 0, len);
		}
	}
}

```
2021年3月4日付けラズパイ64ビットOSのインストール

　最近、ラズパイOSの64ビット版の新しいバージョンが出ていたのでインストールしました。

:::note info
　2022年2月2日に正式版がリリースしました。インストールする様子は[こちら](https://www.denshi.club/parts/2022/02/raspberry-pi-os-64-bit-1.html) に書きました。
:::
 

###ハード
- ラズパイ4 4GB
- USBメモリ 64GB（USB3.0）

###ダウンロード

　[ここから](http://downloads.raspberrypi.org/raspios_arm64/images/)ダウンロードします。

<img width="400" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/2e86aaf7-a5e3-be2d-192b-d710c8b721f6.png">
　4/9のファイルをクリックします。


<img width="500" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/d57b4809-caf5-7c7c-bac3-9e20d7570f7f.png">

　zipファイルをダウンロードしました。
　解凍します。


<img width="450" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/cf6834fb-6f43-511e-8462-091e220cc760.png">

###Raspberry Pi Imagerで書き込む
　PCのUSB3.0にUSBメモリを差し込みます。
　PCでRaspberry Pi Imagerを立ち上げ、Operating Systemのメニューの最後にあるUse custumを選択し、解凍したimgファイルを指定します。StorageはUSBメモリを選択します。


<img width="350" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/8416db85-f533-1c3b-7c9b-860a6f1ad5a1.png">

　書き込みます。

<img width="350" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/6be2da7c-aaee-456a-0c5b-08f8dbcc743a.png">

###USBメモリを差し込んで
　ラズパイから、SDメモリを抜きます。書き込みのすんだUSBメモリを差し込み、電源を入れます。

<img width="500" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/e5e7a56e-a214-9b12-0950-c0731fb79909.png">

<img width="400" alt="ファイル名" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407635/a9f15b90-15c7-4765-42a8-2426a348e9ff.png">
電話番号をクリックorタップして電話をかけさせる方法

```<a href="tel:00-000-000">00-000-000</a>
```
リンクをクリックすると次のような画面が出てくる
![スクリーンショット 2021-04-13 19.22.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1317277/039c8fa4-37ce-8a66-60b8-f818bd0ec239.png)
環境変数とは

環境変数とはパソコン内で使える変数の様なものです。
そもそも「変数とは？」となる方も多いと思います。私自身もつい最近まで
理解しずになんとなく設定してたので私が最近学んで理解できたことを
噛み砕いて共有できればっと思います。
私自身まだ初心者なので記事の内容のアドバイスがあれば頂きたいです！！

##環境変数とは
上記でも記載させていただいたのですが、「環境変数とはパソコン内で使える変数の様なもの」です。
変数とは何かと言いますと「値を入れておける箱の様なもの」です。
例えば、「山田太郎」を「name」と言う変数（箱）に入れます。
そうした場合、「name = 山田太郎」の様になると思われます。
これがざっくりとはしていますが変数の考え方です。
なので、環境変数とは値（山田太郎）を箱（name)に入れてパソコン内だったらその箱から値を取り出して使えるシステムです。
【Rails】画像をasset pipelineを使わずに静的に表示する方法 & image_tagでid/クラス/altを指定する方法。

Railsで画像をasset pipeline（image_tag）を使わずに静的に表示する方法について。

##対処法
app > public配下に画像を保存し、src属性にpublic配下のパスを記述する。

・`<img src="public配下の画像パス" alt="">`


**▼例**
public/assets/imgs/bear-icon-blue.svg　を読み込む場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/23fdb08a-7902-f9af-c7e0-2e503f8e44dd.png)

```erb:
<img src="assets/imgs/bear-icon-white.svg" alt="">
```

<br>
**▼ブラウザの表示**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/ec41e4bf-e785-0644-bfcc-72d693ab1695.png)


画像の読み込みに成功。


###注意点
assets配下の画像をsrc属性で指定して読み込むことはできない。NotFoundのエラーが出る。(昔のRailsでは読み込めたらしい)


<br>
##asset pipelineで読み込む方法
Railsでより一般的なのはasset pipelineを使う方法。
この場合、asset > images配下と、public配下のどちらでも読み込むことができる。


・asset > images配下：　パスの冒頭に`/`不要。
・public配下：　パスの冒頭に`/`が必要。


###1. asset > images配下の場合
・`<%= image_tag 'asset > images配下の画像パス' %>`

**▼実例**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/afa4dc7e-bf1e-4107-bd8e-fa8db41ee630.png)

```erb:
<%= image_tag 'bear-icon-white.svg' %>
```

<br>
###2. public配下の場合
・`<%= image_tag '/public配下の画像パス' %>`

**▼実例**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/23fdb08a-7902-f9af-c7e0-2e503f8e44dd.png)

```erb:
<%= image_tag '/assets/imgs/bear-icon-white.svg' %>
```


<br>
##images_tagでid, class, altを指定する方法
`属性名: "値"`で記述する。

```
 <%= image_tag "画像パス", id: "id名", class: "クラス名", alt: "alt名", width: "幅" , height: "高さ" %>
```


<br>
**▼実例**

```erb:
<%= image_tag 'bear-icon-white.svg', class: "icon-mage", alt: "白熊" %>
```

`:`の後ろにスペースがなくても機能する。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/a0a630d3-936f-a262-bb7f-0e18c5e9cc7c.png)|
|:--|


<br>
以上。
[Chrome拡張] backgroundスクリプトでローカルストレージの値をローカル変数として使う


## うまくいかなかったこと

Chromeの拡張の`chrome.webRequest.onHeadersReceived`でローカルストレージのデータ取得したいけど、なぜかawaitが待たない。。。
本格的にやるならライブラリ使ったりした方が良いが取り急ぎ対応したい。

```backgroun.js

// リクエストを捕捉するAPI
chrome.webRequest.onHeadersReceived.addListener(
  function () {
    // ここでローカルストレージのデータ参照したいが、非同期処理がうまく動かない
  },
  {
    urls: ["<all_urls>"],
    types: ["main_frame", "sub_frame"],
  },
  ["blocking", "responseHeaders"]
);
```

```popup.js
  // ブラウザアクションのスクリプトでローカルストレージを更新している

  // フィールド情報をchromeストレージにセットする
  function setStorage () {
    
    // ローカルストレージにセット
    chrome.storage.local.set({
      hogehoge: hogehogeString,
      pikapika: pikapikaString,
    }, function(){});

  }
```

## 非同期処理を書かずに対応する

ローカルストレージの変更を検知するリスナーが存在することがわかったので、これを使って変更後の値を変数に設定します。
`chrome.storage.onChanged`をイベント登録して変更後の値を変数に代入していきます。

```backgroun.js
var hogehoge = '';
var pikapika = '';

// 読み込み時にローカルストレージの値を変数に設定
chrome.storage.local.get(
  [
    'hogehoge',
    'pikapika'
  ],
  function(storage){
    hogehoge = storage.hogehoge;
    pikapika = storage.pikapika;
  }
);

// ローカルストレージの変更を検知する
chrome.storage.onChanged.addListener(function(changes, area) {
  
  // ローカルストレージの変更か？
  if (area !== "local") {
    return;
  }
  
  // changesは変更したプロパティの配列
  if ("hogehoge" in changes) {
    hogehoge = changes.hogehoge.newValue; // 変更前の値はoldValueプロパティに持つ
  }
  if ("pikapika" in changes) {
    pikapika = changes.pikapika.newValue;
  }

});

// リクエストを捕捉するリスナー
chrome.webRequest.onHeadersReceived.addListener(
  function () {
    alert(pikapika + hogehoge);
  },
  {
    urls: ["<all_urls>"],
    types: ["main_frame", "sub_frame"],
  },
  ["blocking", "responseHeaders"]
);
```


これでbackgroundで動くスクリプトの変数とローカルストレージの値を同期できます。
無駄が多いがロジック部分にコールバックなど非同期処理のコードがなくなるし、わりとありか🧐
@JvmOverloadsとは

**JavaからKotlinのデフォルト値を持つクラス、または関数を呼び出せるようにするアノテーション。**

Javaでデフォルト値はサポートされていないため、以下の`Greeting#sayHello`を呼び出すとコンパイルエラーになります。

### NG

```kotlin
class Greeting {
    
    fun sayHello(prefix: String = "Mr.", name: String) {
        println("Hello, $prefix $name")
    }
}
```
```java
public class JavaClass {
    public static void main(String[] args) {
        Greeting greeting = new Greeting();
	// prefixを引数に渡していないのでエラーになる。
        greeting.sayHello("Bob");
    }
}
```
`Greeting#sayHello`に`@JvmOverloads`を付与することで、Javaからデフォルト値を持つ関数を呼び出せるようになります。

### OK
```kotlin
class Greeting {
    @JvmOverloads
    fun sayHello(prefix: String = "Mr.", name: String) {
        println("Hello, $prefix $name")
    }
}
```
```java
public class JavaClass {
    public static void main(String[] args) {
        Greeting greeting = new Greeting();
        greeting.sayHello("Bob");
    }
}
```

### 参考
- [developers/デフォルトの関数オーバーロード](https://developer.android.com/kotlin/interop?hl=ja#function_overloads_for_defaults)
- [Calling Kotlin Code from Java](https://developer.android.com/codelabs/java-friendly-kotlin?hl=ja&continue=https%3A%2F%2Fdeveloper.android.com%2Fcourses%2Fpathways%2Fandroid-week5-languages%3Fhl%3Dja%23codelab-https%3A%2F%2Fdeveloper.android.com%2Fcodelabs%2Fjava-friendly-kotlin#4)
【Rails】コンパイルした時にクラス属性の値が更新されない時の対処法

Railsのアプリケーションでファイルを更新してコンパイルしたのにブラウザに表示されるクラス属性が変わらない状況が発生したので、その対処法。

##事象
クラス属性のアンダーバーをハイフンに変更し、コンパイル後リロードしたがブラウザに反映されなかった。

```erb:index.html.erb
<div class="top_wrapper">
```

↓

```erb:index.html.erb
<div class="top-wrapper">
```


##対処法
`-`と`_`はコンパイル時に差分とみなされていない様子。

アルファベットを変更してリロードし、そこから変更したいクラス名に変更すると反映される。

```erb:index.html.erb
<div class="top_wrapper">
```

↓ ダミーの変更を挟み、リロード

```erb:index.html.erb
<div class="top">
```

↓　本来変更したいクラス名に変更

```erb:index.html.erb
<div class="top-wrapper">
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563526/30a73c84-ab07-7502-d0d4-885c8b676dcf.png)


無事変更が反映された。
Git ブランチを作ってリモートに push & 追跡 までをやってくれるエイリアス作った

## 説明
ブランチを作るときに、`git checkout -b` して〜 `git push origin HEAD` して〜 が面倒くさかったので、エイリアスを作った。

## 登録するエイリアスコマンド
`vi ~/.zshrc` して以下のコマンドを追記＆保存する

```zsh:~/.zshrc
alias fd="git fetch origin develop:develop"
alias branchcreate='(){git checkout -b $1 && fd && git reset --hard origin/develop && git push origin HEAD && git branch -u origin/$1}'
```

終わったら反映コマンドを叩く

```zsh
source ~/.zshrc 
```

## 使い方
以下のコマンドを叩くと最新化した develop からローカルにブランチを作ってリモートにプッシュ＆追跡までをやってくれる

```zsh
branchcreate feature/hogefuga
```
変数名のルールとよく使われる命名記法②

# 変数名の命名記法
プログラムの中では変数名の名前の付け方が統一されていると解りやすい

一般的に使用されている命名記法には3つの種類がある

##キャメルケース

`別名：ローワーキャメルケース`

**特徴**
>最初の単語は全て小文字
2つ目の単語は先頭の文字を大文字にして、他は小文字にする

**参考例**

- let userName;
- let totalScore;

## パスカルケース

`別名：アッパーキャメルケース`

**特徴**

全ての単語の先頭文字を大文字
他は全て小文字にする

**参考例**

- let UserName;
- let TotalScore;

## スネークケース

**特徴**

全ての単語を小文字
単語と単語をアンダーバー`_`で繋げる

**参考例**

- let user_name;
- let total_score;


## 定数

**特徴**

全ての文字を大文字
単語と単語をアンダーバー`_`で繋げる

**参考例**

- const MAX_SIZE = 10;


### 補足情報

他にも単語と単語をハイフン`-`で繋げる
`ケバブケース`があるが、JavaScriptでは`-`が
使用できないので使用されない
python　演算子を使って計算する

##初めに 
初学者です。アウトプットすることで定着を目的としています。

### 演算子を使い計算結果を表示する
では、まず簡単な式からやっていきます。
ちなみに計算結果を表示するには、`print関数`を使いカッコの中に式を書いていきます。

```python
print( 1 + 2 * 3 )
```
上記の結果は`7`です。
上記の文を日本語に直して読んでみると`数値2に数値3をかけた結果を数値１に足して結果を表示しろ`になります。
すごく簡単な文ですが何点かポイントがあります。
###ポイント 
１つ目は`python`の計算式も優先順位があり`足し算`,`引き算`より先に`掛け算`,`割り算`が優先される点。
２つ目は、カッコの中から式を優先すると言うこと。
もし上記の式で先にprintが優先されていた場合、表示結果は`1+2*3`になっているはずです。
また、複数の計算をするときもこれは当てはまります。例えば上記の式にカッコを付け加えてみます。

```python
print( (1 + 2) * 3)
```
すると、カッコの中の`1+2`の優先順位が先になり`数値１に数値2を足した結果に数値3を掛けて表示しろ`になり結果は`6`になります。
3つ目は数値は文字列ではないので『'』や『"』で囲わないことです。

###主な演算子のまとめ
では主な演算子をまとめます。

|演算子        |計算式     |     
|:------------|:---------|
|+            |足し算     |
|-            |引き算　　　|
|*            |掛け算     |
|/            |割り算　　　|
|//           |割り算（小数点は切り捨て）|
|%            |余り算     |
他にもありますが上記の表が主な演算子です。
ちなみに恥ずかしながら余り算が最初理解できなかったのですが、
要するに割り算で余った数を出すことだそうです。

```py
>>> print(11%5)
1
```

上記の例だと`数値11を数値5でわり余った数値1を表示する`と言うことです。
VAEによる画像検索システム

Fashion-MNISTを利用して、類似画像の検索システムを作成しました。方法としては、VAEにより次元圧縮をして、潜在空間上で距離が近いものを検索結果としました。

ソースコードは以下から触れます。

https://colab.research.google.com/drive/1O7IUZiue_RQtz3kfxFVqGblfzx96EIqV?usp=sharing

# データについて
Fashion-MNISTは70,000サンプルのファッション商品の写真で、以下のようになっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678160/59656e96-3621-6aa7-9f11-e1f66ea024a3.png)

各ラベルは以下のようになっています。（このラベルは直接的には使いませんが、検索した際に同じラベルのものが出力されたら、有効性を見出せるという意味で使用します。）

| ラベル | 記述 |
| --- | --- |
| 0 | T-shirt/top |
| 1 | Trouser |
| 2 | Pullover |
| 3 | Dress |
| 4 | Coat |
| 5 | Sandal |
| 6 | Shirt |
| 7 | Sneaker |
| 8 | Bag |
| 9 | Ankle boot |

※データセットの配布元： [GitHub「fashion-mnist／zalandoresearch」](https://github.com/zalandoresearch/fashion-mnist/blob/master/README.ja.md)。The MIT License (MIT) Copyright © [2017] Zalando SE, https://tech.zalando.com
※出典： Fashion-MNIST: a Novel Image Dataset for Benchmarking Machine Learning Algorithms. Han Xiao, Kashif Rasul, Roland Vollgraf. [arXiv:1708.07747](https://arxiv.org/abs/1708.07747)


また、ネットワークは以下のようなものを用います。

### エンコーダー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678160/701ca786-c657-d7c8-183b-e8c4fd5726dc.png)
### デコーダー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678160/f8d5e6ce-b224-8989-6d2f-c78a4ce2f561.png)




# VAEの結果
作成したVAEモデルは以下のような結果になりました。

- 訓練結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678160/14d6644d-d9a2-6484-b515-2d6e0127c39b.png)

最初はテストデータの誤差が異常に大きくなっていましたが、正常に訓練できています。

- 再現画像
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678160/732c6552-aa56-cce1-928d-4b4187ef5bc1.png)

上段が訓練データ、下段がテストデータで、隣合う二つが元画像と再現後の画像となっています。
概ね再現できているとみて問題なさそうです。

# 検索結果
index=15の画像に対して、似た画像を検索しました。distanceが距離（2乗和）です。

```
	index	distance	label
0	15	0.000000	3
1	4648	0.801960	3
2	15393	1.194853	3
3	16060	1.561346	3
4	10346	1.677270	3
5	13806	1.683182	3
6	1672	2.047508	3
7	1921	2.118745	3
8	13082	2.165989	3
9	2797	2.166618	3
10	4243	2.315314	3
11	15704	2.385199	3
12	15119	2.390874	3
13	13158	2.433088	3
14	7793	2.462667	3
15	4905	2.485209	3
16	7603	2.495291	3
17	11167	2.570958	3
18	11551	2.619137	3
19	5991	2.628919	3
```

画像で見ると以下のようになっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678160/eb2c9f0c-8eee-6fc0-984c-8685ad2d28fd.png)

左上が検索に利用した画像で、似ている画像が順番に上段の左から右、下段の左から右に表示されています。
なお、検索する画像・検索対象の画像はテストデータのものを用いています。



検索結果としては、概ね同じラベルのものが返ってきていますし、実際の画像も似ている雰囲気のものが抽出されているので、似ているものを抽出する機構としてはうまくいっているように感じます。実は最初はCIFAR-10でやろうとしていたのですが、カラー画像だとVAEの学習がどうしてもうまくいかないようだったので、白黒のデータセットであるFashion-MNISTに変更しました。
実用上は（一応グレスケにすれば可能ではありますが）カラー画像でできることが重要だと考えられるので、今後の課題としたいと思います。

# ソースコード
https://colab.research.google.com/drive/1O7IUZiue_RQtz3kfxFVqGblfzx96EIqV?usp=sharing

# 参考文献
- [VAEとGANを活用したファッションアイテム検索システム](https://techblog.zozo.com/entry/retrieval_using_vae_gan)
- [PyTorch＋Google ColabでVariational Auto Encoderをやってみた](https://qiita.com/koshian2/items/b6402d3b4494dcd6d6a1)
三項演算子とNull合体演算子 By php

# 三項演算子とNull合体演算子

## ?:
```php
if ($Foo) {
    echo $Hoge
} else {
    echo $Fuga
}
```
は

```php
echo $Foo ? $Hoge : $Fuga
```
とかける

## ??
```php
if (isset($Foo)) {
    echo $Foo
} else {
    echo $Hoge
}
```
は

```php
echo $Foo ?? $Hoge
```
とかける
機械学習初心者がface_recognitionライブラリを使ってつまずいたところ

顔画像認識アプリを作成するにあたって、つまずいたところをメモとして書き留めます。

スクレイピングで集めてきた画像から顔だけ切り取りをしたいけど、OpenCVだと正常に切り取れない！（耳だけ切り取られた画像が出力されたなど）ということがあったので、face_recognitionライブラリを使って顔だけ切り取りを行いました。
その際にエラーが発生し原因が分からず、悩んでしまったのでメモします。
（著作権に引っ掛かってしまいそうなので、画像の添付は省略させていただきます）

使用環境
* google colaboratory
* face-recognition-1.3.0  

## 顔の特徴量が見つけられない場合、発生するエラー

例えば横向きの画像を以下のコードで切り取りを行おうとすると

```python
#face_recognitionはpip install する必要あり
#!pip install face_recognition
import face_recognition
import cv2

#jimin.jpgは横向きの画像
img_cv2 = cv2.imread('jimin.jpg')

image = face_recognition.load_image_file('jimin.jpg')
face_locations = face_recognition.face_locations(image, model='cnn', number_of_times_to_upsample=2)
print(face_locations)

#顔の切り出しを行うために各変数に値を保持する
top = face_locations[0][0]
right = face_locations[0][1]
bottom = face_locations[0][2]
left = face_locations[0][3]
print('top:',top, 'right:',right, 'bottom:',bottom, 'left:',left)

#顔のトリミング
img_face = img_cv2[top:bottom, left:right]
#トリミングした画像を保存
cv2.imwrite('jimin_change.jpg',img_face)
```

以下のエラーが発生しました（横向きの画像なので顔の切り取りができないのは承知です）。
（実際に使用したデータは顔の輪郭がぼけていたりしていました）


```
[]
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-9-a65f96f2cfc8> in <module>()
     10 
     11 #顔の切り出しを行うために各変数に値を保持する
---> 12 top = face_locations[0][0]
     13 right = face_locations[0][1]
     14 bottom = face_locations[0][2]

IndexError: list index out of range
```

変数face_locations が [] と出力されました。

face recognitionライブラリの公式のサイトhttps://face-recognition.readthedocs.io/en/latest/face_recognition.html#face_recognition.api.face_locations
を見てみると、返り値は` A list of tuples of found face locations in css (top, right, bottom, left) order ` と記載がありました。
確かに配列が出力されています。

私がやりたかったのは、指定したディレクトリ内の複数の画像から顔の切り出しを行うことだったので、顔が認識されずにエラーになってしまうのは不都合でした。
（for文でディレクトリ内のファイルを読み込んで顔の切り取りを行いたかったので、途中でエラーが発生するとなかなか作業が進まない、、、）

## 顔の特徴量が見つけられない場合は、その画像をそのまま出力させてしまおう

とにかくエラーを回避するために以下のようにコードを修正しました。

```python
#face_recognitionはpip install する必要あり
#!pip install face_recognition
import face_recognition
import cv2

#画像読み込み
img_cv2 = cv2.imread('jimin.jpg')
#画像のサイズ取得
width = img_cv2.shape[0]
height = img_cv2.shape[1]

image = face_recognition.load_image_file('jimin.jpg')
face_locations = face_recognition.face_locations(image, model='cnn', number_of_times_to_upsample=2)
print(face_locations)

#face_recognition.face_locations()で顔が認識されない場合、[]が返るので最初に読み込んだ画像をそのまま返す
if face_locations == []:
  face_locations = [(0,width,height,0)]

#顔の切り出しを行うために各変数に値を保持する
top = face_locations[0][0]
right = face_locations[0][1]
bottom = face_locations[0][2]
left = face_locations[0][3]
print('top:',top, 'right:',right, 'bottom:',bottom, 'left:',left)#出力>>>top: 156 right: 722 bottom: 461 left: 418

#顔のトリミング
img_face = img_cv2[top:bottom, left:right]
cv2.imwrite('jimin_not_change.jpg',img_face)

```

以下、出力内容です。jimin_not_change.jpgというファイルが生成されました。

```
[]
top: 0 right: 600 bottom: 488 left: 0
True
```

顔の特徴量が見つからない場合は元の画像を出力させて、指定したディレクトリ内の画像すべてを上記のコードで処理したあと、顔の切り取りができなかった画像は手動で削除する方針で解決しました。
うまく切り出せない画像はそんなに多くなかったので手動でいけました。



他に良い方法があれば教えていただけると幸いです。
IntelliJのPlantUMLプラグインで、Dockerで立てたサーバーを使う

文章は後で書く・・・はず・・・

```bash
$ docker run --rm -p 9999:8080 plantuml/plantuml-server:jetty
```

![スクリーンショット 2021-04-13 17.33.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58650/519306d3-e225-be4b-7bdc-db7d66c43c31.png)

![スクリーンショット 2021-04-13 17.31.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58650/5a4b76b3-648d-8e95-4615-fa950fb94e40.png)
Libtorchで時間をはかる

```C++
#include <cuda.h>
#include <cuda_runtime.h>
    ...
    auto start = std::chrono::steady_clock::now();
    ...
    cudaDeviceSynchronize(); // 現在までにGPUに依頼した仕事が、全部終了するまで待つ
    auto end = std::chrono::steady_clock::now();
    std::chrono::duration<double> elapsed_seconds = end - start;
    std::cout << "preprocessData time: " << elapsed_seconds.count() << "s\n";
```
RaspberryPi 4で HSP3を動かした話

#0. あいさつ
はじめましての方は初めまして。しがない大学生のあめふりてる*と申します。
今回は、RaspberryPi 4でHSP3を動かす挑戦をしたので、それの備忘録のようなものを書いていきたいと思います。

#1. 環境
今回の環境は以下の通りです。

コンピュータ : [RaspberryPi 4 Model B 4GB](https://www.amazon.co.jp/gp/product/B086M9YNW6?pf_rd_r=0VQAT5NF5T9ZWZSM51W1&pf_rd_p=7626af39-b716-47c8-84eb-9679f177dc53&pd_rd_r=c8a2edb3-7c84-448d-9538-f5b5f9466399&pd_rd_w=cCo8W&pd_rd_wg=sRZYm&ref_=pd_gw_unk)
OS : Ubuntu 20.04.2 LTS

RaspberryPi 4にOSをインストール / セットアップするのは、こちら記事を参考にさせていただきました。
[Raspberry Pi 4でUbuntuデスクトップを動かして遊ぶ-@y-tsutsuさん
](https://qiita.com/y-tsutsu/items/b50d44bd70c25279d130)

#2.インストールのためのセットアップ

##1. gitのインストール
HSP3をインストールするために、まずはgitをインストールします。
端末を開き、以下のコマンドを打ち込んでください。

```
sudo apt-get install git
```

これで、gitがインストールされたはずです。
本来なら、ここで初期設定をするのですが、今回はこのままで問題ないので省略します。

##2. HSP3のダウンロード
GitHubから、OpenHSPをクローンします。以下のコマンドを打ちましょう。

```
git clone http://github.com/onitama/OpenHSP
```

インストールが終わったら、セットアップしていきましょう。

##3. 必要なパッケージのセットアップ
依存パッケージがあるのでそれのインストールをします。
以下のコマンドを順番に打っていってください。途中で、Y/nを求められますが、すべてYでOKです。

```
sudo apt-get update
sudo apt-get install -y libgtk2.0-dev
sudo apt-get install -y libglew-dev
sudo apt-get install -y libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev
sudo apt-get install -y libgles2-mesa-dev libegl1-mesa-dev
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562969/c357354b-a493-5dad-e992-faf44a875a9f.png)

#3. HSP3のインストール
さて、いよいよHSP3をインストールしていきます。
まずは、ディレクトリを移動します。

```
cd OpenHSP
```

その後、makefileを書き換えます。
PaspberryPi 4 Model Bは、arm64アーキテクチャなので、書き換えないと動かないようです。ここでかなり苦労しました。
CFLAGS_GPに「-DPNG_ARM_NEON_OPT=0」というオプションを一つ追加します。

ファイルからOpenHSPのあるフォルダに移動して、makefileをテキストエディタで開きましょう。その後、CFLAGS_GPを書き換えます。

```
~略~

CFLAGS_GP = -Wno-write-strings --exec-charset=UTF-8 -DHSPDISH -DHSPDISHGP -DHSPLINUX -DHSPDEBUG -DPNG_ARM_NEON_OPT=0 -I src/hsp3dish/extlib/src  -I src/hsp3dish/extlib/src/glew -I src/hsp3dish/gameplay/src -std=c++11

~略~
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562969/76e20cca-bc8a-875e-1f50-d688d8d8072f.png)

書き換えが終わったら、保存して、端末に戻ります。
その後、以下のコマンドを打ちましょう。

```
make
```

30分ぐらい時間がかかるので、珈琲を飲みながら待ちましょう。
エラーが出なければ、インストールできています！お疲れさまでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562969/fef2de33-de75-a5cd-0a74-29b9b4a65863.png)

#4. サンプルコードを動かしてみる

私の環境では、コマンドによるコンパイルがうまくいかなかったので、エディタから実行させます。
以下のコードを打ちましょう。

```
./hsed sample/block3.hsp
```

その後、出てきたエディタを選択し、F5を押しましょう。
すると、ブロック崩しができます！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562969/6c27f938-bb26-0c7b-50e2-9b0623823463.png)

#INF.最後に
最後まで読んでいただきありがとうございます。
私自身、Linuxに不慣れだったり、アーキテクチャの理解が不十分だったりでなかなか難しかったのですが、Linuxで動かせるようになったのはいいことです！
今後、raspberryPiをアプリケーションサーバにして、何か面白いことができたらなぁと考えています。

この記事がよかったらLGTMやストックお願いします。それではまたどこかで。
さくらのクラウドのオブジェクトストレージをTerraform + AWSプロバイダーで操作する方法

2021年4月に正式サービス化された[さくらのクラウドのオブジェクトストレージ](https://cloud.sakura.ad.jp/specification/object-storage/)をTerraformから操作する方法について記載します。

## はじめに

さくらのクラウド向けのプロバイダー terraform-provider-sakuracloudには`sakuracloud_bucket_object`といったリソースが存在するのですが、これは旧オブジェクトストレージ向けで現在では利用できなくなっています。
(近いうちに該当コードは削除される予定です)

代わりにAWSプロバイダーを利用することでオブジェクトストレージの一部操作が可能となっています。この記事ではAWSプロバイダーを利用してオブジェクトストレージを操作する方法について記載します。

## この記事で利用したTerraform/AWSプロバイダーのバージョン

- Terraform: v0.14
- AWSプロバイダー: v3.36.0 

## 前提条件

- バケットの作成はAPIから行えないためTerraformからは行えません
- バケットに対する操作(ACL/CORS/バージョニングの設定など)は↑の理由から行えません

## 準備

- さくらのクラウドのコントロールパネルからサイト/バケットを作成しておく  
  (参考: https://manual.sakura.ad.jp/cloud/objectstorage/about.html#objectstrage-site-create)
- サイト作成時に表示されるアクセスキー/シークレットを控えておく
- コントロールパネルからバケットを作成する

## tfファイルの作成

こんな感じのtfファイルで操作できます。

```hcl
# 利用するプロバイダーを宣言
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.0"
    }
  }
}

# さくらのクラウド向けにAWSプロバイダーを設定
provider "aws" {
  alias      = "sacloud"
  region     = "jp-north-1"
  access_key = var.s3_access_key
  secret_key = var.s3_secret_key
  endpoints {
    s3 = "https://s3.isk01.sakurastorage.jp"
  }

  skip_credentials_validation = true
  skip_region_validation      = true
  skip_requesting_account_id  = true
  skip_metadata_api_check     = true
}

#================================================

# アクセスキー/シークレットを設定する
variable "s3_access_key" {
  # 直接tfファイル上に書く場合は以下コメントアウトを解除して記載する
  #default = "your-access-key"
}
variable "s3_secret_key" {
  # 直接tfファイル上に書く場合は以下コメントアウトを解除して記載する
  #default = "your-secret-key"
}

#================================================

# 作成済みのバケットを参照
data "aws_s3_bucket" "example" {
  provider = aws.sacloud

  bucket   = "your-bucket-name" #作成したバケット名を指定
}

# オブジェクトの作成
resource "aws_s3_bucket_object" "object" {
  provider = aws.sacloud

  bucket = data.aws_s3_bucket.example.id
  key    = "example.txt"
  source = "example.txt"
  etag   = filemd5("example.txt")
  acl    = "public-read"
}
```

アクセスキーは実行時に指定するか環境変数や.tfvars経由で指定しておいてください。
バケット名については`aws_s3_bucket`の`bucket`部分を各々の環境に合わせて書き換えてください。

指定可能なパラメータについては以下ドキュメントを参照してください。
参考: [aws_s3_bucket_objectのドキュメント](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_object)

なお`acl`については`public-read`と`private`のみが利用可能なようです。
(他の値を指定してもapplyでエラーにならない点に注意)

また、`provider "aws"`ブロックでは`access_key`と`secret_key`を直接書く形にしていますが、Shared Credentials File(`~/.aws/credentials`みたいなやつ)も使えるはずです。  
参考: [AWSプロバイダー: Shared Credentials File](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#shared-credentials-file)

### 注意点

`aws_s3_bucket_object`の全てのパラメータが利用できるとは限りません。
(試していませんがおそらく`storage_class`などは指定しても無視されるかエラーになると思います)

ご利用の際は各自で必要な動作確認を行ってください。

---

以上です。
Windows10でVLAN設定をする（RealtekのUSB-GigaEtherで）

# VLANの設定
Windows10では、LANアダプタの構成でVLANが設定できるらしい。
今回使用したPCはDELL Latitude7400 2-in-1。アダプタはDELLのDA100です。
DA100はUSB-CでPCとつなぐとHDMI、VGA、DP、1GBE、USB-C、USCB3.0がついたドッキングステーションです。
![dev.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133769/e44b4d93-b6a5-fde6-c1ea-0043279ad98e.png)
デバイスマネージャーで見るとRealtekのチップを使っているようです。

# Windows10のネットワークアダプタ設定から（失敗）
「スタートメニュー」－「設定」－「ネットワークとインターネット」－「イーサネット」－「アダプタのオプションを変更する」－「イーサネットXX」（Realtek USB GbE Family Controller..）と書いてあるものを右クリック－「プロパティ」－「構成」をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133769/1aafbcb5-a3b4-271e-1595-f0d991c14a12.png)
詳細設定のプロパティでVLAN IDにVLANIDを設定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133769/16efb740-ef97-2251-ea44-161a81d4cdca.png)
ところがパケットキャプチャしても、全タグVLANが流れてて通信できない・・・。

# Realtekのツールを探す
ネットを探していると、Intel PROSetを使っている方はIntelのユーティリティを使うと設定できるとの情報がありました。
そこで、Realtekにも同様のツールがないか捜索・・・。
https://www.realtek.com/ja/component/zoo/category/network-interface-controllers-10-100-1000m-gigabit-ethernet-usb-3-0-software
Realtekのダウンロードページから、Diagnostic Program for Win7/Win8/Win10をダウンロードしてインストールします。
起動するときには、DA100をつないでおきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133769/8d9129ff-82c5-44fd-5968-5801c1e2cc91.png)
起動するとこんな感じ、
VLANの項目をクリックして、VLANを選択し、「追加」ボタンをクリックして、VLANIDを入力するのみ。
これでTagを必要なVLANで通信できます。
Gatsbyプロジェクトで特定ページのWebクローラーをブロックする

## はじめに
今回はGatsbyで作ったWebサイトに適切に検索クローラをコントロールする方法から検証まで記載しました。

ページの品質が低い、問い合わせ用のページなど、特定のページをGoogle検索に出したくない。また想定外のページが結果上位に出てきてしまうことがありえます。。。
あらかじめ、クローラーに対して命令することで上記のようなことを回避して、検索からのより良いファーストビューを提供しましょう。

ちなみにGatsbyスターターのadminはnoindexタグによってインデックスを拒否しているので、今回設定する必要はありません。※設定されていないスターターもあるかも。。。

## robots.txtを生成するプラグインを導入する
robots.txtファイルを生成するプラグインを使用します。一緒にsitemapを生成するプラグインも追加します。
これでrobots.txtとsitemapがルート直下に作成されます。

```

// プラグインをライブラリに追加
$ yarn add gatsby-plugin-robots-txt

// sitemapがない場合は同時に追加しておく
$ yarn add gatsby-plugin-sitemap
```

`gatsby-config.js`に追加したプラグインの記述を追加します。
複数のパスを登録する際は、配列で指定します。詳しい生成ルールについてはプラグインの[GitHubページ](https://github.com/mdreizin/gatsby-plugin-robots-txt)を参照してください。

```gatsby-config.js
plugins: [
    {
      resolve: 'gatsby-plugin-robots-txt',
      options: {
        host: 'https://www.example.com',
        sitemap: 'https://www.example.com/sitemap.xml',
        policy: [
          { 
            userAgent: '*', 
            disallow: ['/blog', '/contact', '/tag', ]  // クロール禁止のパスを配列で指定
          }
        ]
      }
    },
    'gatsby-plugin-sitemap',
  ]
```

上記の後、`gatsby build`すると、public配下に`robots.txt`と`sitemap.xml`が生成されます。

生成した`robots.txt`の中身はこちら。disallowに指定したパスが追記されていることがわかります。

```robots.txt
User-agent: *
Disallow: /blog
Disallow: /contact
Disallow: /tag
Sitemap: https://www.example.com/sitemap.xml
Host: https://www.example.com
```

## 検証
想定通りにrobots.txtが記載できているかは[Google Search Console](https://search.google.com/)を使います。

こちらからrobots.txtのテスト画面に飛びます。サイトの登録がまだの方は登録が必要です。
[robots.txt テスターで robots.txt をテストする](https://support.google.com/webmasters/answer/6062598?hl=ja)

テスト対象のURLで検証を実行します。
結果がブロック済みであれば、クローラー対象外となっていることが確認できます。
![スクリーンショット 2021-04-13 0.42.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/537165/b9fbe741-9d9e-53b5-0793-6def7fa7589c.png)

あとはしばらく待って自分のサイトがクローリングされるのを待ちます。
しばらくするとGoogle Search Consoleのカバレッジから、robots.txt によってブロックされていると結果が表示されます。
【macOS】rmコマンドでディレクトリを削除する

#はじめに
macOSなどUNIX系OSではrmコマンドでファイルを削除できます。しかししrmコマンドにディレクトリを指定すると次のようなエラーが表示され、削除出来ません。

```zsh
rm dirname: is a directory
```

ここでは、その解決方法を記載します。

#-rf オプションを使用する
-r オプションはrmコマンドの削除対象に、ディレクトリを含めるように指定します。
-f オプションはエラーを表示させないオプションです。
この２つのオプションを組み合わせる事で、確認なしディレクトリを削除できます。

```zsh
rm dirname -rf
```

#rmdirコマンドを使用する
rmコマンドの替わりにrmdirコマンドを使用します。

```zsh
rmdir dirname
```

ただし、このコマンドを使用する際に削除したいディレクトリが空でない場合には次のようなエラーが表示されます。

```zsh
rmdir: dirname: Directory not empty
```
Rails　チュートリアル第二章


#rakeコマンドとrailsコマンド
Rails 4以前ではRakeを使っているため、
古いRailsアプリケーションを扱うためにはRakeについて学ぶ必要があります。


おそらくもっとも頻繁に使われていたRakeコマンドは、データベースのデータモデルを更新するためのrake db:migrateコマンドと、自動化されたテストスイートを実行するためのrake testコマンドの２つでしょう。

また、Rails 4以前のアプリケーションでは、rakeコマンドのバージョンをGemfileで定義しているため、Bundlerのbundler execコマンドを通して実行する必要があります。


したがって、例えばRails 5におけるマイグレーションコマンドは次のようになりますが、

 ```
 $ rails db:migrate
```
Rails 4以前では、次のように実行する必要があります。

``` 
 $ bundle exec rake db:migrate
```

## Rakeの特徴
>Rubyで記述ができる
>Rakefileというファイルに一連の処理を定義する （この処理のまとまりを「タスク」と呼ぶ）


##bundle exec
・bundle execをつけないと、Gemfile.lockに基づかずにgemのバージョンが決定される
・bundle execをつけると、Gemfile.lockに書かれているバージョンのgemが動く


・railsコマンドだけはbinを省略してもbin/railsと解釈される
なので、railsコマンドは何も付けずに実行
・binディレクトリにファイルが存在するコマンドはbin/◯◯
・それ以外のコマンドはbundle exec ◯◯



参考文献
bundle execって必要なの?
https://qiita.com/d0ne1s/items/fa2dafcee02e963fe997
Railsのrakeってなんぞ？
https://qiita.com/SuguruOoki/items/e736b15bbb80eacf66d7#dsldomain-specific-language%E3%81%A8%E3%81%AF



#RESTfulな設計
まずRESTについて簡単に解説しておきます。RESTとはアプリケーションの設計方法の1つで、操作の対象となるリソースをURLを使って表し、それに対してHTTPメソッドの「GET」「POST」「DELETE」「PUT」を使って操作を行なうというものです。あるURLへGETを使ってアクセスすれば、結果を取得でき、同じURLへPUTでアクセスすれば新しく作成されるよう設定を行ないます。

Railsのアプリケーションの場合、対象となるリソースはデータベースのテーブルがほとんどです。このリソースを表すURLが例えば「http://localhost:3000/sample」だったとします。RESTの考え方に従えば、この1つのURLに対してHTTPメソッドのGETでアクセスすればデータを取得し、PUTでアクセスすればデータの作成が行われるようにします。

Railsでは利用者からのリクエストで呼び出されるのはアクションですので、URLとHTTPメソッドの組み合わせ毎に呼び出されるアクションをルーティングとして設定すればいいことになります。
引用

https://www.javadrive.jp/rails/routing/index5.html#:~:text=REST%E3%81%A8%E3%81%AF%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE,%E3%82%92%E8%A1%8C%E3%81%AA%E3%81%86%E3%81%A8%E3%81%84%E3%81%86%E3%82%82%E3%81%AE%E3%81%A7%E3%81%99%E3%80%82&text=Rails%E3%81%AE%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E5%A0%B4%E5%90%88,%E3%81%AE%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%81%8C%E3%81%BB%E3%81%A8%E3%82%93%E3%81%A9%E3%81%A7%E3%81%99%E3%80%82

###rails rutes詳細
引用

https://pikawaka.com/rails/rake_routes

## Active Record 
引用
https://railsguides.jp/active_record_basics.html

##resources
```ruby
resources :photos
```
上の記述により、アプリケーション内に以下の7つのルーティングが作成され、いずれもPhotosコントローラに対応付けられます。

引用

https://railsguides.jp/routing.html