OmniAICreator/Qiita-1.07M huggingface dataset:
iOSアプリリリースで、誰も教えてくれなかった10のこと

今週、iOSアプリをリリースしました。
[Purelist](https://apps.apple.com/us/app/purelist/id1549367431)という、とびきり書きやすいリスト型のライティングアプリです。
たぶん使えば言っている意味がわかってもらえるかと思います。

リリース後1週間、いくつか想定外のことがあったのでリストにしました。
これを読んで少しでもプロモーションやアプリストアのスクショの改善に役立てていただけると幸いです。

**1. リリース後にプロモーションしない限り、ほぼ誰にも見つけてもらえない
2. プロモーションしてもほぼ埋もれるし、インストールされない
3. レーティングは国別に表示される
4. サブタイトルは結構重要
5. プロモーション用テキストと概要は同じ場所に表示される
6. Store用アイコンは透過していなくても透過してるよって注意される
7. App Analyticsの更新時間はバラバラ
8. オプトインユーザーが少ないのでデータを拾いにくい
9. 自分がオプトインユーザーになるとデータをとりにくい
10. フィードバックはApp Storeでもらいにくい**

## 1. リリース後にプロモーションしない限り、ほぼ誰にも見つけてもらえない
リリースしてから12時間、何もせずにいたら自分（デザイナー）とエンジニアしかインストールしませんでした。

その後、Product Hunt、Twitter広告、Facebook広告、Apple Search Ads、Instagramに流してやっと何百かインストールしてもらえました。

## 2. プロモーションしてもほぼ埋もれるし、インストールされない
USやEU、インドを中心とした話ですが、Twitter広告とFacebook広告は配信してクリックがあってもインストールまではほぼ到達しません。
3%〜4%くらいしかインストールしません。
クリエイティブやプロモーション文と実際のアプリストアに差を感じたのかもしれませんが、個人的にはレーティングがないとほぼインストールに至らないという仮説を立てています。

App StoreでリリースしたらApple Search Adsを使うのが一番コスパいいです。

Product Huntはよほど世界的に愛されるサービスか、100人くらい継続的にProduct Huntを利用している知り合いがいれば有利です。
知り合いがいない場合は土曜日か日曜日に情報を発信するのが有利です。
サイトを見る人も少ないですが、投稿する人も少ないので、その分TOPに載りやすくなります。
できれば日曜日の方が、月曜日にサイトを閲覧した人にも届きやすいのでいいと思います。

## 3. レーティングは国別に表示される
上にも仮説として書きましたが、レーティングがないとインストールに至る確率は下がると感じています。
そのため、レーティングを知人に頼んで稼ぐことができても、それは他の国では全く見られていないということです。

ターゲットとしている国が母国ではないのであれば、なるべくターゲット国を絞った状態でプロモーション等をすることをお勧めします。
でないとレーティングが分散し、誰からも微妙にしか相手にされていないアプリになります。

## 4. サブタイトルは結構重要
App Storeに掲載される、サブタイトルはSEO的にかなり重要になります。
ここに検索キーワードとなるような語句を入れておいた方がいいです。

[Apple Search Ads](https://searchads.apple.com/)のTOPにも記載してある通り、検索結果画面からそのままインストールする人は65%ほどいます。

検索画面に表示されるのはスクショ、サブタイトル、レーティング、タイトルです。
この4つはかなり重要な情報なので慎重に言葉選びや画像選びをすることをお勧めします。

## 5. プロモーション用テキストと概要は同じ場所に表示される
App Store Connectをみるとプロモーション用テキストと概要の入力欄があるが、同じ位置に表示されるものなので、同じ文章を書くとおかしくなります（おかしくなりました）

![Asset 2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/500709/7e019a1e-597b-8d85-c7b3-f27aa43ddfff.png)

![Asset 1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/500709/9b65dc4c-53ec-0df4-0096-a87b0040ed26.png)


## 6. Store用アイコンは透過していなくても透過してるよって注意される
Macのプレビューで画像を開いて保存時に透過のチェックを外すのを忘れずに。。。

## 7. App Analyticsの更新時間はバラバラ
毎日20時に更新されると思ってたけど全然間違いでした。
16:00に更新されることもあれば、朝4:00になっても更新されないことがあります。
諦めて寝ましょう。

スマホもパソコンもバラバラでした。

## 8. オプトインユーザーが少ないのでデータを拾いにくい
リテラシー高いのはいいことだけども！！
オプトインユーザー、つまりAppleへのデータの提供をOKと言ってくれてるユーザーですが、かなり少ないです。
Appleのアナリティクスしか使用していない場合、十分なデータを取るには十分なオプトインユーザーの数が必要です。
なので、データにならないことがだいぶあります。

## 9. 自分がオプトインユーザーになるとデータをとりにくい
iPhoneの初期設定時にAppleにデータを送信するか聞かれるので、それは絶対「送信しない」にしてください。
アナリティクスで自分のデータも含まれてしまい、データの解析がしづらくなります。

## 10. フィードバックはApp Storeでもらいにくい
USやEUは個人主義が進んでいるのか、自分のメディアにフィードバックを記載しますが、App Storeには書いてくれません。
たくさんエゴサしてフィードバックを見つけるしかないです。
なのでエゴサしやすい名前をつけることをお勧めします。

---
以上です。
また期間が空いたら追加したり別の内容を書いたりすると思います。

[Purelist](https://apps.apple.com/us/app/purelist/id1549367431)
Visual Studio 2019で構文チェックから整形まで自動化する方法

# はじめに

Visual Studioで下記を自動で実行する方法について記載します。

- コード分析：Lint/Linter（リント・リンター）と呼ばれる構文をチェックする機能
- コード整形：設定したファイルフォーマットやインデントに従い整形する機能

# 環境
Visual Studio 2019 Version 16.8.4

# コード分析
### 有効化
メニューバーから、
「ツール＞オプション＞テキストエディター＞C/C++＞コードスタイル＞リンター」を開いて

「コードリンターの有効化」をFalseからTrueに変更
![Linter.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691672/335b9ea2-ac4b-95f5-2b45-ca391ca73bd1.png)

### 設定
上記メニュー内のチェッカー欄で警告レベルの変更ができます。
項目ごとに下記設定を行うことで、チェック結果を「表示＞エラー一覧」のウィンドウ上で確認できます。

- なし：指摘されない
- 提案事項：メッセージとして通知
- 警告
- エラー

![2021-01-23_23h02_23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691672/94cd8d71-dd03-70b8-b843-e91abe75b092.png)

### 手動での実行方法
メニューバーから、
「ビルド＞ソリューションでコード分析を実行」を選択する

### 自動での実行方法：ビルドのタイミング

- ソリューションエクスプローラー上で、プロジェクトを右クリックして「プロパティ」を選択
- 「構成プロパティ＞コード分析」を開く
- 「ビルドに対するコード分析の有効化」を「はい」にする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691672/78575ab8-8a86-f67b-9d75-c735c2bbe4fd.png)

# コード整形
### 設定
メニューバーから、
「ツール＞オプション＞テキストエディター＞C/C++＞コードスタイル＞書式設定」を開いて
各種項目を設定してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691672/fd6078c8-4450-d4df-b8ef-3ac7e21b1b9d.png)

### 手動での実行方法

- ファイル全体：`Ctrl+K` `Ctrl+D`
- 選択している行のみ： `Ctrl+K` `Ctrl+F`

参考：[VS/インデントなどコードを整形するショートカットの紹介](https://windev.just4fun.biz/?VS/%E3%82%A4%E3%83%B3%E3%83%87%E3%83%B3%E3%83%88%E3%81%AA%E3%81%A9%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92%E6%95%B4%E5%BD%A2%E3%81%99%E3%82%8B%E3%82%B7%E3%83%A7%E3%83%BC%E3%83%88%E3%82%AB%E3%83%83%E3%83%88%E3%81%AE%E7%B4%B9%E4%BB%8B)

### 自動での実行方法：保存のタイミング
標準機能には無いので、拡張機能を利用します。

メニューバーから、
「拡張機能＞拡張機能の管理」を開いて、

下記どちらかをインストールします。
- [Format document on Save](https://marketplace.visualstudio.com/items?itemName=mynkow.FormatdocumentonSave)：今回必要とする機能のみ提供してくれるシンプルな拡張機能
- [Productivity Power Tools 2017/2019](https://marketplace.visualstudio.com/items?itemName=VisualStudioPlatformTeam.ProductivityPowerPack2017)：色んな機能がてんこ盛りな拡張機能
    - インストール後、「ツール＞オプション＞Productivity Powers Tools」を開く
    - 「Format document on save」にチェックを入れる


# 他の環境に設定をコピーしたい場合
メニューバーから、
「ツール＞オプション＞テキストエディター＞C/C++＞コードスタイル＞全般」を開いて
「設定から .editorconfig ファイルを生成」ボタンをクリックしてください。

コード分析、コード整形ともに設定を記録することができます。

.editorconfig の詳細については[こちら](https://qiita.com/takeshisakuma/items/c22b59a5e394b4ce6cee)が分かりやすかったのでご参照ください。
![2021-01-23_23h09_35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691672/56e6879a-12c1-818b-ad2f-ab1294c60759.png)

---

以上です。
railsで簡単ログイン（ゲストユーザーログイン機能）を実装する方法

今回はポートフォリオを見てもらう確率を上げるために必須な、簡単ログインの実装方法を書いていきます。

# 開発環境
Mac OS Catalina 10.15.7
ruby 2.6系
rails 6.0系

# 前提
devise導入済み
通常の新規登録、ログイン、ログアウト機能に関しては実装済み
投稿機能ができるアプリを作っており、postsモデルとpostsコントローラーが登場しますが、ご自身の例に置き換えてご理解ください。

# ルーティング設定

まずはルーティングを設定します。

```rb
# HTTPメソッドはpostで、'/posts/guest_sign_in'というURLでpostsコントローラーのnew_guestアクションを参照する
post '/posts/guest_sign_in', to: 'posts#new_guest'
```

```routes.rb
Rails.application.routes.draw do
  devise_for :users
  root to: "posts#index"
  # 次の１行を追加
  post '/posts/guest_sign_in', to: 'posts#new_guest'
  resources :posts do
    resources :comments, only: [:create, :destroy]
    collection do
      get 'search'
    end
  end
  resources :users, only: :show
  post 'like/:id' => 'likes#create', as: 'create_like'
  delete 'like/:id' => 'likes#destroy', as: 'destroy_like'
end
```

# コントローラーにnew_guestアクションを記述

それでは次にpostsコントローラーにアクションを定義していきます。
deviseのメソッド find_or_create_by や sign_in を使っていますので、気になる方は調べてみてください。
また、パスワードは SecureRandom.alphanumeric を用いてランダム生成しつつも、全て英字、全て数字のパスワードが生成されないように工夫しています。

参考：https://qiita.com/take95/items/61b181449b38d4415fc3

```posts_controller.rb
def new_guest
  # emailでユーザーが見つからなければ作ってくれるという便利なメソッド
  user = User.find_or_create_by(email: 'guest@example.com') do |user|
  # 自分はユーザー登録時にニックネームを必須にしているのでこの記述が必要
  user.nickname = "ゲスト"
  # 英数字混合を必須にしているので、ランダムパスワードに、英字と数字を追加してバリデーションに引っかからないようにしています。
  user.password = SecureRandom.alphanumeric(10) + [*'a'..'z'].sample(1).join + [*'0'..'9'].sample(1).join
  end
  # sign_inはログイン状態にするデバイスのメソッド、userは3行目の変数userです。
  sign_in user
  # ログイン後root_pathに飛ぶようにしました。
  redirect_to root_path
end
```
また、deviseでメール確認機能を実装済みの場合、user.confirmed_at = Time.nowを追加する必要があります。

```posts.controller.rb
def new_guest
  user = User.find_or_create_by(email: 'guest@example.com') do |user|
  user.nickname = "ゲスト"
  user.password = SecureRandom.alphanumeric(10) + [*'a'..'z'].sample(1).join + [*'0'..'9'].sample(1).join
  # 以下一文を追加
  user.confirmed_at = Time.now
  end
  sign_in user
  redirect_to root_path
end

```

# ビューを追加

簡単ログインのリンクをヘッダーに追加します。
自分の場合は部分テンプレートに切り出しているので、その部分テンプレート内の記述を編集します。

コンソールでrails routesを打ってパスを確認しましょう。その後ヘッダーに次の1文を追加します。

```
<li><%= link_to 'ゲストログイン(閲覧用)',posts_guest_sign_in_path, class: "guest-login", method: :post %></li>
```

この時、HTTPメソッドをつけ忘れないように注意してください



```_header.html.erb
<nav>
  <ul class='lists-right'>
    <% if user_signed_in? %>
    <li><%= link_to current_user.nickname, user_path(current_user.id), class: "user-nickname" %></li>
    <li><%= link_to 'ログアウト', destroy_user_session_path, method: :delete, class: "logout" %></li>
    <% else %>
  # 以下1文を追加
    <li><%= link_to 'ゲストログイン(閲覧用)',posts_guest_sign_in_path, class: "guest-login", method: :post %></li>
    <li><%= link_to 'ログイン',new_user_session_path, class: "header-login" %></li>
    <li><%= link_to '新規登録',new_user_registration_path, class: "sign-up" %></li>
    <% end %>
  </ul>
</nav>
  
```

以上で簡単ログイン(ゲストユーザーログイン機能)を実装できました。
参考になれば幸いです。
ネットワークスペシャリスト試験を受けることにしました【令和3年春季】

# ネットワークスペシャリスト試験
https://www.jitec.ipa.go.jp/1_11seido/nw.html

## きっかけ
応用情報処理技術者（AP）を取得してから数年経っているので、そろそろ高度情報資格が欲しくなったのと、勉強日記的に。

## 進捗(随時更新)

 - [1/31 #1 NW試験は午前問題で基礎固めできるか？](https://qiita.com/foxtail1979/private/eae37660ec6849cb9ecd)
 
 - [2/7 #2 続・ネットワークスペシャリスト試験の基礎固め
](https://qiita.com/foxtail1979/private/040645f9a8e3867e8c16)

 - [3/26 #3 午後試験で必要な基礎知識は午前Ⅱでは身に付かない？](https://qiita.com/foxtail1979/items/d7a122addef3b016c06d)

 - [3/26 #4 IPA講評の「正答率が高かった／低かった」の傾向](https://qiita.com/foxtail1979/items/015e02eb0053ed29a7fb)

 - [4/5 #5 午後Ⅱに歯が立たない件](https://qiita.com/foxtail1979/items/0afe855ce9437c3cded3)
 
 - [4/24 #6 試験を終えて振り返り](https://qiita.com/foxtail1979/items/8795caccb21f7dcfae26)

 - [6/28 #7 合格発表の日](https://qiita.com/foxtail1979/items/5fcdab0a85b230fb3c08)
 
## 方針
書籍での独学の想定です。

 - [ネットワークスペシャリストドットコム](https://www.nw-siken.com/)  
   午前Ⅱの過去問をたくさん解いて慣れようかなと。

 - [ネスペR1 - 本物のネットワークスペシャリストになるための最も詳しい過去問解説](https://www.amazon.co.jp/dp/4297113279/)  
   午後試験は特化した対策が必要かなと思ったので、本屋さんでみて一番ノリが合いそうな本を選ぼうかなと。

 - [2020 ネットワークスペシャリスト 「専門知識+午後問題」の重点対策](https://www.amazon.co.jp/dp/4865751998/)  
   午後試験の対策の一環で。

## 現状
CCNA(直近の改訂前)を持っているので、基本的な知識は身についているものと信じています。

## スケジュール
午前試験をそこそこに、午後試験の対策を重点的にやろうかなと思っています。基礎固めが重要そうなら、午前対策を伸ばすかな？
・午前Ⅱの過去問解くのを2週間(〜2/10)
　→基本知識が足りなそうなら追加で対策。
・午後試験の対策(〜4/10)

本番は4/18(日)です。

# 試験に向けて
ひとまず頑張ってみます。
【Java】AtCoderのABC-189に参加しました。

こんばんは。

2021/1/23に、AtCoderのABC-189に参加しました。
レートは以下の通りとなっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402487/b7a21947-8483-3eba-3a53-a599c529d80c.png)


https://atcoder.jp/users/ishikawaryou

C問題は処理時間でエラーになり、良いロジックを思いつけず負けました・・。
まだまだですね。
ともあれレートを13→51に更新！
A問題は5分以内、B問題15分以内で安定して解けるようになってきました。
半年前に始めたときはA問題ですら会社の昼休み中（1時間-お弁当の時間）に解けなかった事を思うと、着実な進歩です。

###A問題

入力した3文字が全部同じか、そうでないかチェックするというもの。
String型で入力した文字列を、char型にして同じかチェックしました。

```java
import java.util.Scanner;
import java.util.HashSet;
import java.util.Set;

public class Main{
public static void main(String args[]){
Scanner sc = new Scanner(System.in);
  String c = sc.next();
  if((c.charAt(0)==c.charAt(1))&&(c.charAt(1)==c.charAt(2))){
System.out.println("Won");  
  }else{
System.out.println("Lost");  

  }
}
}
```


###B問題
飲んだアルコール飲料の容量（v）と、アルコール度数（p）から、摂取したアルコール量（al）を求め、アルコール許容量（x）を超えて酔っぱらうかどうかを調べます。

整数型での答えを求められていましたが、int型は小数点以下を切り捨ててしまうので、思い切って数字を100倍して、アルコール度数10.5%→1050と算出させるようにしました。
もっとスマートなやり方があると思うんですけどね・・。

```java
import java.util.Scanner;
import java.util.HashSet;
import java.util.Set;

public class Main{
public static void main(String args[]){
  Scanner sc = new Scanner(System.in);
  int n = sc.nextInt();
  int x = sc.nextInt();
  int v[] = new int[n];
  int p[] = new int[n];
  int al = 1;
  char flg = '0';
  for(int i=0;i<n;i++){
    v[i] = sc.nextInt();
    p[i] = sc.nextInt();
    if(i==0){
    al = v[i]*p[i]; 
    }
    else
    {
    al = al+(v[i]*p[i]); 
    }
    if(al>x*100){
      System.out.println(i+1);
      flg = '1';
      i=n;
    }
      //System.out.println("al/100 " + al/100);
  }
  
  if(flg=='0'){
      System.out.println(-1);
  }
  
}
}
```

###C問題
＊不正解のためソースは割愛します。
ロジック自体は正解に近づいていたようですが、処理時間がかかりTLEとなりました。
（21ケースAC、12ケースでTLE）。

やはり2重ループはだめでしたね。

###感想
週末にちょっとした（失礼？）戦いがあるのは、いい刺激になります。
僕はこれでも高校時代は数学が好きで得意科目だったので、少し高校時代の数学の楽しさを思い出してきて楽しいです。これなら継続できそうな気がします。

これからもコツコツ取り組んで、茶色を目指したいと思います！
同じく灰色レベルで頑張っている方、お互い頑張りましょう！
【Vue.js】v-onディレクティブの省略記法

```indx.html
<div id="app">
  <button v-on:click="clickHandler">
    click1
  </button>
  <button @click="clickHandler">
    click2
  </button>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
```
```main.js
var app = new Vue({
	el: "#app",
  methods: {
    clickHandler: function() {
    	alert('がんばれ')
    }
  }
})
```

v-on:clickでも@clickでもどちらでも大丈夫。
エンジニア未経験がWordPressを使ってWEBアプリを作ってみた

# 今回製作したWEBアプリについて


今回作成したWEBアプリは「[AboutMyself](https://www.aboutmyself.net "AboutMyself")」。プロフィールを質問形式で記載していくSNSのようなものです。15年程前に流行った「前略プロフ」をイメージしていただければ良いかと思います。![IMG_7162.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402394/45134b81-7d71-3a65-51b7-a4b032d68773.png)

#1. 開発経緯

インターンのテレワークをするなかで、新しく入ってきた人のこと(趣味や経歴)についてわからずなかなかコミュニケーションが取りづらいと思った。また、気難しいと思っていた上司の趣味がわかった途端、急に親近感が沸いた。これらのことから、ある程度事前に相手のことをわかっていればコミュニケーションが円滑になるのではないかと考え、「AboutMyself」を作ることになった。

#2. 「[AboutMyself](https://www.aboutmyself.net "AboutMyself")」の想定利用ケース

**人と深く関わりたい人の場合**
* 人と会う機会が減ったなかで、ユニークなプロフィールを通して親交を深めたい。
* プロフィールを通して相手のことを知りたい。
* プロフィールを通して初対面の人と仲良くなるきっかけを作りたい。

**そんなに深く関わりたくない人の場合**
* プライベートで利用しているLINEやFacebookなどを教え合う仲ではないけど連絡は取りたい。
* グループも作成できるので、何かについてざっくばらんに議論や質問などをしたい。

![スクリーンショット 2021-01-24 0.04.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402394/25713f4f-1377-986b-b9a2-ade04b5bcc5b.png)
![スクリーンショット 2021-01-24 0.04.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402394/ba28ca6a-2d67-9b58-ea52-cd943085dbb3.png)



#3. 開発工程

1. お名前.comからドメインを取得し、同時にレンタルサーバーも申し込み。
2. レンタルサーバーのコントロールパネルからWordPressをインストール
3. SNS作成にはもってこいのプラグイン「BuddyPress」を使用。テーマは「GeneratePress」を使用。
4. その他ログイン、ログアウトに関するプラグインを使用。
5. ある程度機能が備わったらデザインの微調整をし、自分でパソコン3台、スマホ2台を使いテスト。
6. テストに問題がなければ、友人に使用してもらいフィードバックをもらう
7. フィードバックを元に完成段階まで完了。
ここまで5日ほど。

#4. 今後の「AboutMyself」について

今後は、多くの人に利用してもらうようマーケティングに重きを置き、フィードバックを元に改善していく予定。この記事をみた方もぜひ、アクセス、ユーザー登録していただきたいです！お願いします！

#5. 最後に

今はユーザー0ですが、何か進捗があればGoogle Analyticsの画像と共に報告できればなと思います。
初めての執筆なので、めちゃくちゃな文章でしたが最後までご覧いただきありがとうございました！

[AboutMyself](https://www.aboutmyself.net "AboutMyself")」
Word VBAのグループ化が時々失敗する

## 事象
C#で [NetOffice](https://github.com/NetOfficeFw/NetOffice) を使ってWordの中のオートシェイプをグループ化する要件があった。その際に時々成功するが、時々失敗するという事象に悩まされたので、ここにメモしておく。

具体的には以下のようなコードで問題が発生した。

```C#
private void Group(Word.Document document, string[] names) 
{
    // namesはグループ化対象のShapeたちのNameが入っている
    object[] args = names.OfType<object>().ToArray();
    var range = document.Shapes.Range(args);
    range.Select();
    var group = range.Group(); // <-- ここで落ちる
}
```

例外の内容

```
System.UnauthorizedAccessException: 選択した図形はグループ化できません。
```

## 原因
２つあった。
### Wordが見えてなかった
高速化の観点からWordを非表示にしていて実行していたが、Group化する際にはVisibleがtrueじゃないといけない(Wordが見えてないといけない)ようだ。

### Shapeがあるページに遷移していない
グループ化対象のShapeが見えない位置にあると、上記の`UnauthorizedAccessException` が出るようで、例えば1ページ目にShapeがあれば成功するが、2ページ目にあると失敗するという現象が発生した。 

## 対処
今回の場合、以下のようなVisible操作とページ遷移コードを`range.Group()` の前に実行しておく必要があった。

```C#
Application.Visible = true;
Application.Selection.GoTo(WdGoToItem.wdGoToPage, WdGoToDirection.wdGoToAbsolute, {該当ページ});
range.Group();
```

これで安定してグループ化することができました。
Anacondaの仮想環境の構築について

## Anacondaの仮想環境周りのコマンド

### 仮想環境作成
    conda create -n 環境名 python=バージョン

### 現在作成している環境確認
    conda info -e

### 環境切り替え
    conda activate 環境名 

### 仮想環境削除
    conda remove -n 環境名 --all

### 環境の保存
    conda env export -n 環境名 > 保存したいファイル名.yml
Couldn't open CUDA library libcupti.so.9.0

## 現象
普段, cudaを使って深層学習をしているのですが, GPUをRTX3080に変更して, cudaのバージョンを変更した際に, 当たった壁について記録.

プログラムをtensorflowを使って書いていました. そして, GPUを使って, CNNの学習を回そうとした際に次のエラーが. 

`Couldn't open CUDA library libcupti.so.9.0`

## 原因
LD_LIBRARY_PATHの先に, libcupti.so.9.0のファイルが無かったためだった.
## 解決策
LD_LIBRARY_PATHのパスの指定先を, ファイルのある場所にする.

    export LD_LIBRARY_PATH=ファイルのある場所
でパスを指定する. 大体, usr/local/cuda のあたりにある感覚. (感覚ですみません)

    export -p
で, パスの指定先を確認できる.
PHP ログイン認証の作成手順③　〜新規登録機能作成②とパスワードハッシュ化〜

新規登録フォームからPOSTで送られてきたデータをデータベースにINSERTする

#手順
##ユーザを登録する処理
register.phpでバリデーションに引っかからずに登録ができる準備が整った時の処理をコーディングしていく。
UserLogicクラスを作成し、その中のcreateUserメソッドを作成し、それを使用する。
createUserメソッドはtrueかfalseを返すような関数だから、新規登録に失敗した時には、
$err配列に格納して、バリデーションと同じようにエラー項目として表示させる。

```php:register.php
<?php

require_once('../classes/UserLogic.php');

// エラーメッセージ
$err = [];

// バリデーション
if(!$username = filter_input(INPUT_POST, 'username')){
    $err[] = 'ユーザ名を記入してください';
}

if(!$email = filter_input(INPUT_POST, 'email')){
    $err[] = 'メールアドレスを記入してください';
}

$password = filter_input(INPUT_POST, 'password');
// 正規表現
if(!preg_match("/\A[a-z\d]{8,100}+\z/i", $password)){
    $err[] = 'パスワードは英数字８文字以上１００文字以下にしてください。';
}

$password_conf = filter_input(INPUT_POST, 'password_conf');
if($password !== $password_conf){
    $err[] = '確認用パスワードと異なっています';
}

if(count($err) === 0){
    //ユーザを登録する処理
    $hasCreated = UserLogic::createUser($_POST);

    if(!$hasCreated){
        $err[] = '登録に失敗しました';
    }
}
?>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ユーザ登録完了画面</title>
</head>
<body>
<?php if (count($err) > 0) : ?>
<!-- エラーがある場合にforeachで該当エラーを表示させる -->
    <?php foreach($err as $e) : ?>
    <p><?php echo $e ?></p>
    <?php endforeach; ?>
<!-- $err配列に何もない＝エラーがない　から完了画面を表示させる -->
<?php else: ?>
    <p>ユーザー登録が完了しました。</p>
<?php endif ; ?>
<a href="signup_form.php">戻る</a>
</body>
</html>
```

###UserLogicクラスを作成する
createUserメソッドでPOSTで送られてきたデータを引数にとる。
そして、送られてきたユーザ名、メールアドレス、パスワードを$arr配列に格納して、
prepareで用意したINSERT文のプレースホルダーに入れる。

```php:UserLogic.php
<?php
require_once('../dbconnect.php');

class UserLogic
{
    /**
     * ユーザを登録する
     * @param array $userData
     * @return bool $result
     */
    public static function createUser($userData)
    {
        $result = false;
        $sql = 'INSERT INTO users (name, email, password) VALUES (?, ?, ?)';

        // ユーザデータを配列に入れる
        $arr = [];
        $arr[] = $userData['username'];
        $arr[] = $userData['email'];
        $arr[] = password_hash($userData['password'], PASSWORD_DEFAULT);
        try{
            $stmt = connect()->prepare($sql);
            $result = $stmt->execute($arr);
            return $result;
        }catch(\Exception $e){
            return $result;
        }
    }
}

?>
```
Railsのマイグレーション関連のコマンドをまとめてみた

#開発環境
・Rails6.0.0

#マイグレーションファイルの生成とテーブル作成
###マイグレーションファイルの生成は次の2パターン
#####①モデルを生成して自動で作られる場合
【コマンド】rails generate model モデル名
これにより、「db/migrate」の中に自動的にマイグレーションファイルが生成される。

#####②自分で作る
既存のテーブルにカラムを追加したい場合など。
(例)usersテーブルにnameカラム（型：string）を追加したい場合
【コマンド】rails generate migration add_name_to_users name:string

###テーブルの作成
【コマンド】rails db:migrate
これでマイグレーションファイルの内容がテーブルに反映される。
結果はSequel Proなどでデータベースを更新して確認できる。

ちなみにターミナル上でマイグレーションファイルがテーブルに反映されているか確認することもできる。
【コマンド】rails db:migrate:status
![実行結果](https://i.gyazo.com/ef4f6b01a70304fa126be58257d974eb.png)
「Status」が「up」になっていればテーブルに反映されている状態、「down」になっていればまだmigrateされていない状態です。

#マイグレーションを取り消したい時
開発中に、マイグレーションファイルの編集が完了していないのにrails db:migrateを先走って実行してしまった場合など。
パニックにならずに以下のコマンドを実行しましょう。
【コマンド】rails db:rollback

これにより上の画像の「Status」の部分が「up」から「down」に変更され、migrateする前の状態に戻ります。これでマイグレーションファイルを再度編集できるようになります。

※厳密にはマイグレーションファイルは編集しようと思えばいつでも編集できますが、**「up」状態のマイグレーションファイルを編集してしまうとエラーの原因になるので必ずrollbackしてから編集**し、再度migrateしましょう。

#「up」状態のマイグレーションファイルを削除してしまったら？
###①削除されたファイルの代わりとなる仮のマイグレーションファイルを生成
rails db:migrate:statusを実行し、削除済みファイルの「Migration ID」を確認したうえで同じIDを持つマイグレーションファイルを作成。
ファイル名： 「(MigrationID).sample.rb」など

###②以下のコマンドが実行できるようになるので、実行。
【コマンド】rails db:rollback

###③以下のコマンドでマイグレーションの状態を確認。
【コマンド】rails db:migrate:status
①で仮作成したマイグレーションファイルの「Status」が「down」になっていることが確認できる。
この時点で、仮作成したファイルは削除してしまいましょう。

**これでテーブルとマイグレーションの状態の整合が取れました！**
TF1.15＋EagerExecution環境で、TensorBoardログを出力する方法

# 概要
TensorFlow1.15でEager Executionを使用したコードを実装しているのですが、TensorBoardログ出力の実装に手間取ってしまいました。せっかくなので備忘録として記事に残しておきます。

## 結論
TensorFlow1.15＋EagerExecution環境でTensorBoardログを出力する場合、「tf.compat.v2.summary」を使うのがよさそうです。言いたいことはこれだけです。以降はすべて蛇足です。


## 困ったこと
TensorFlow2系でTensorBoardログを出力する場合、「tf.summary.create_file_writer」を使用してwriterを作成するのが一般的だと思います。

しかし、TensorFlow1.15で「tf.summary.create_file_writer」を使用すると、AttributeErrorが出てしまいました。どうやら、1系のAPIが呼び出されてしまうようです。

```
AttributeError: module 'tensorflow._api.v1.summary' has no attribute 'create_file_writer'
```

## 途中で試行錯誤したこと

いまさら1系の実装は避けたい。。ということで、[公式サイトを参考](https://www.tensorflow.org/tensorboard/migrate)に「tf.contrib.summary.create_file_writer」に書き換えてみました。すると、一歩前進し、エラーが解消してTensorBoardログが生成されるようになりました。よし。

続いて、「tf.contrib.summary.scalar」を使用してscalar値を出力しようと試みました。しかし、ログファイルのサイズは1KBのまま変わらず、一行に大きくなりません。
ここで色々悩み時間をつぶしてしまいましたが、google先生経由で調べた結果、[githubのissueに該当記事](https://github.com/tensorflow/tensorflow/issues/32588)がありました。その記事の一部を抜粋します（とても参考になりました）。

```
We should not recommend the usage of tf.contrib.summary in eager mode.
tf.compat.v2.summary (or tf.summary in TF2) should be used in this section.

With tf.contrib.summary, we need to use always_record_summaries() or record_summaries_every_n_global_steps() (#32587) to record events even in eager mode. This is very unnatural and confusing.
```

どうやら、eagerモードで「tf.contrib.summary」を使用してログ出力する場合には、「always_record_summaries()」や「record_summaries_every_n_global_steps()」を使用する必要があるとのこと。試していませんが、少し面倒そう。

## 最終的にうまくいった方法

そこで、上記issueの内容にしたがって、「tf.compat.v2.summary」を使用するように変更しました。すると、エラーも起きず、TensorBoardログのファイルサイズも大きくなりました。正しく記録されていることも確認できました。今回使用したAPIは以下の通りです。

 * writer作成：tf.compat.v2.summary.create_file_writer
 * ログ出力（例）：tf.compat.v2.summary.scalar、tf.compat.v2.summary.histogram
 

これで１日がつぶれてしまいました。。こういう本筋と違うところで時間を食うのが辛いところです。。



### 参考サイト

* tf.summaryの使用法をTF2.0に移行する（TensorFlow公式サイト）
https://www.tensorflow.org/tensorboard/migrate
※日本語が変だったので理解しきれませんでしたが、見返したらきちんと「tf.compat.v2」の記述がありました。英語サイトを読めばこんなに苦労しなかったのかも。

* tf.compat.v2.summary should be used in /guide/eager#summaries_and_tensorboard #32588 (Github>Issue)
https://github.com/tensorflow/tensorflow/issues/32588
Notionで日記をつけよう

#はじめに
Notionにはデータベースの機能があります。とても便利です。その中にカレンダーがあります。日付にページを紐づけることが可能です。日付に紐づけることで日記にちょうどいいなぁと思ってしました。しかし、カレンダーから日記を作成しなくても、別で書いた日記をカレンダーにリンクさせる方法はないかと思考錯誤して、今回紹介することに至りました。
##使う機能
- カレンダー
- データベース
- create linked database

##流れ
1. ページにデータベースのカレンダー生成する。
2. 任意の場所にカレンダーを移動させる。（私は右に寄せて、左側に日記をリスト化して表示させています。）
3. `/linked`と入力する。
4. 先ほどのカレンダーを選択する。（予めカレンダーのタイトルをつけておくと探しやすいです。）
5. 日付を入れることで、カレンダーにも反映される。


---
1.ページにデータベースのカレンダー生成する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/741816/d282f6ca-576c-3312-5185-08e3cb779ce0.png)

2.任意の場所にカレンダーを移動させる。（私は右に寄せて、左側に日記をリスト化して表示させています。）


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/741816/43c1ab87-6672-1666-aafb-1bca584c8286.png)

3.`/linked`と入力する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/741816/f6a96f67-1034-b606-207e-c5eaa339e2d6.png)


4. 先ほどのカレンダーを選択する。（予めカレンダーのタイトルをつけておくと探しやすいです。）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/741816/1ef1110d-e944-1798-631b-dc97b0d7a880.png)
5. 日付を入れることで、カレンダーにも反映される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/741816/13b45354-b26d-7daf-c477-febc94412afc.png)

##最後に
私は同じページ内でリンクさせていますが、別ページのカレンダーにもリンクさせることができます。
カレンダーやリストで表示させたいプロパティを変更することも可能です。
今回、左側はデフォルトの表のようなデータベースでしたが、ビューを変更させることも可能です。
レスポンシブページの作り方

# 導入

最近レスポンシブなwebページを作っています。
大まかに言うと1024px未満の横幅を持つデバイスではコンテンツの比率を維持したまま拡縮するように。
1024px以上であれば横幅が変わっても一定のサイズ（例えば1000pxのまま）で見れるようにしています。

そんなページを作る際のテクニックになります。

## 結論
サイズを指定する際の単位に**px**ではなく**rem**を使用します。

SPサイズでデザインが上がってきた場合、320px,375px,414pxというサイズになっていることが多いです。
たとえば375pxのデザインが回ってきたとしましょう。
その場合は以下のようにします。

``` css
html {
  // 基準サイズ（375pxで1pxになるように設定）
  // 1pxになるようにしているのは、remのときに小数点を打つのが面倒だからです
  font-size: calc(100vw / 375);

  @media screen and (min-width: 1024px) {
    // PCサイズでは常に固定
    font-size: 1px;
  }
}
body {
  // 全体的に多用するフォントサイズが10px想定ならbodyで設定します
  font-size: 10rem;
}
```

## 解説
remというのは最上位、つまりhtml要素の文字サイズを基準にした相対な単位です。
htmlでfont-sizeが10pxなら1rem=10px、24pxで設定していたら1rem=24pxになります。

つまりhtml配下の子孫要素に使用する単位をremにすることで、html要素の文字サイズに連動するページが作成できます。
`font-size`は言うに及ばず、`width,height,margin,padding`などにも使えます。
`border`にも使えますが、基準にした横幅(375pxとか）より小さいとピクセルで表した際に0.8pxとかになって消えてしまうかもしれません（未検証です）。

相対指定でコンテンツサイズ大きくなりすぎたり小さくなりすぎるときは`min-width,max-width,min-height,max-height`が使えます。
左右余白を調整して真ん中に寄せたい場合は`margin: 0 auto;`で調整できます。

~~文字サイズは`min-font-size,max-font-size`なんてのがあります。~~
わたしの妄想の産物で、実装されていません。
かわりに`font-sizeでmin関数など`が[使えるブラウザ](https://caniuse.com/mdn-css_types_min)があるようです。
ちなみにmin関数って[こんなもの](https://developer.mozilla.org/ja/docs/Web/CSS/min())です。

わたしはこの辺を使うことでどーにかこーにかレスポンシブなページを実現してます。
KotlinのNull安全とは何か

Kotlinを勉強し始めたのでメモ。
KotlinはNull安全、つまりNull非許容が基本であるということ。

## 何が嬉しいのか

Null非許容で嬉しいのは、コンパイル時点でNullが入り込むのを防いでくれるから。
基本Null許容する言語、Javaなどの場合はプログラム実行時に意図しないNull混入によって、"Null pointer Exception(通称ぬるぽ)"が発生する可能性がある。

```kotlin
  val i: Int = 200
  val j: Int = i // nullじゃないので代入OK

  val k: Int? = null // ?をつけるとNullable（Null許容型になる）
  val l: Int = k // Nullableな変数 k はNull非許容 l への代入不可。Nullが入る可能性を排除している。
```

## Nullableを安全に使用するには safe call

safe callを使う。
Nullable型にnullが入っていれば処理を実行しないようにできる。

```kotlin
// safe call；Nullable型がnullでない場合のみ値にアクセス

  val value = null //ここに値が入る場合は下記のtoString()は実行される。
  val str: String? = value?.toString() //toString()は実行されないのでエラーを防げる。
  println(str) //null
```

## smart cast

参照する値がnull出ないことを確実に知らせておけば、
非Nullの型として扱ってくれる機能をsmart castという。

```kotlin
// Trueならsmart castされる
  if (k != null) {
    println(k.toString()) //safe call しなくてもif文中ではIntとして扱える（?がいらない）
  }
```

## ?:演算子

```kotlin
  println(k ?: 0) //nullなら0を返す
```

## 強制非Null変換

```kotlin
// 非Nullへの変換、極力使わない方がいい。
  var str: String? = "aefe"
  println(str!!.length)
```
Python学習型じゃんけん

# はじめに
- Python を少し囓った素人が、「学習型じゃんけん」を作ってみました。 (⇒ [SQL版](https://qiita.com/tetr4lab/items/656f8f9d3ea68bbe76ec))
- 学習型といっても、強化学習とかではありません。単純な統計です。
- 「こう書いた方がスマートだ」など、突っ込み大歓迎です。

#### 環境
- Jupyter Notebook 6.1.4
- Python 3.8.5 (default, Sep  3 2020, 21:29:08) [MSC v.1916 64 bit (AMD64)]

# アルゴリズム
- 人間は、単純な選択を短時間に繰り返したときに、無意識に癖が出ます。
- 直近4回の手の並びの出現頻度を記録して、直近3回の並びから最も頻度の高い次の手を予測します。
- 初期化時に出現履歴と頻度表を適当な乱数で埋めてあります。

# 使い方
- 人間が手を入力する前に、プログラムは手の内を見せます。
    - 見たくない場合は、`firstOut`を`False`にしてください。
- 人間側の手を`1`～`3`の数字で入力します。
    - 機械側の手を見ずに入力するとフェアです。
    - `0`を入力するとゲームを終了します。
- 人間が手を選ぶと、勝敗を判定し、結果と戦績を表示します。

# コード
```python:janken.py
import random as rnd

# 初期化
log = [rnd.randrange(3) for _ in range(4)] # 履歴
frequency = [[[[rnd.randrange(3) for _ in range(3)] for _ in range(3)] for _ in range(3)] for _ in range(3)] # 頻度
handName = { 0:'Goo', 1:'Choki', 2:'Par' } # 手の名前
prompt = "[1:Goo, 2:Choki, 3:Par, 0:End]? " # プロンプト
human = 0 # 人間の勝利数
computer = 0 # 機械の勝利数
draw = 0 # 引き分け数
firstOut = True # 先出し

# 手の表示
def printHand(hand, isHuman = False, secret = False):
    print(f"{'Human' if isHuman else 'Computer'} hand: {handName[hand]}{(' (secret)' if secret else '')}")

# 結果と戦績の表示
def printResult(comHand, humHand):
    global human, computer, draw
    if comHand == humHand:
        result = 'draw'
        draw += 1
    elif comHand == humHand - 1 or comHand == humHand + 2:
        result = 'Human lose!'
        computer += 1
    else:
        result = 'Human win!!'
        human += 1
    print(f"{result} (computer:{computer} human:{human} draw:{draw})")

# 次の手の取得
def getNextHand(isHuman = False):
    if isHuman:
        while True:
            try:
                hand = int(input(prompt))
            except:
                pass
            else:
                if hand >= 0 and hand <= 3:
                    return hand - 1
            print('input error')
    else:
        f = frequency[log[1]][log[2]][log[3]] # 人間の次の手の出現頻度
        return (f.index(max(f)) + 2) % 3 # 最頻手に勝てる手

# 履歴と頻度の更新
def updateLog(hand):
    global log, frequency
    log.append(hand)
    log = log[-4:]
    frequency[log[0]][log[1]][log[2]][log[3]] += 1

# メインループ
while True:
    print(f"--- {human + computer + draw + 1} ---") # ゲーム数表示
    com = getNextHand() # 機械の次の手の算出
    if firstOut: printHand(com, secret = True) # COMの手表示 先に見せてしまう
    hand = getNextHand(isHuman = True) # 人間の次の手の取得
    if hand < 0: break # 終了
    printHand(hand, isHuman = True) # HUMの手表示
    if not firstOut: printHand(com) # COMの手表示  後で見せる
    printResult(com, hand) # 結果表示
    updateLog(hand) # 記録
```

```text:result
--- 1 ---
Computer hand: Par (secret)
[1:Goo, 2:Choki, 3:Par, 0:End]? 1
Human hand: Goo
Human lose! (computer:1 human:0 draw:0)
--- 2 ---
Computer hand: Par (secret)
[1:Goo, 2:Choki, 3:Par, 0:End]? 2
Human hand: Choki
Human win!! (computer:1 human:1 draw:0)
--- 3 ---
Computer hand: Par (secret)
[1:Goo, 2:Choki, 3:Par, 0:End]? 3
Human hand: Par
draw (computer:1 human:1 draw:1)
--- 4 ---
Computer hand: Choki (secret)
[1:Goo, 2:Choki, 3:Par, 0:End]? 0
```
[Swift]UISliderクラス

#Sliderで透過率を変更する
UISliderクラスを実装することで,理解していきます。
#準備
以下の画像をAssetsフォルダに入れておきます。
![ダウンロード.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/839966/ba422f59-11db-3168-050f-e1c765aec923.jpeg)
#実装
+ボタン(Library)→showtheimagelibraryからflowerを選択して、ViewControllerに配置します

<img width="300" alt="スクリーンショット 2021-01-23 23.22.43.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/839966/f30535ce-9a27-b313-dab1-6b0d710940b1.png">
UISliderをViewControllerに接続する時に、ConnectionをActionに変更して、TypeをUISliderに変更します。
<img width="300" alt="スクリーンショット 2021-01-23 23.30.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/839966/38d22952-01fc-7d47-ef4a-e02df434f108.png">
以下のように、コードを書いて実行すると写真のalphaを変更することができます。

```ViewController.swift

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var flower: UIImageView!

    @IBAction func UISlider(_ sender: UISlider) {
        flower.alpha=CGFloat(sender.value)
    }
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
      
    }
}


```
スライダーを自由に動かして写真のalphaを変更することができました。
<img width="300" alt="スクリーンショット 2021-01-23 23.34.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/839966/a2f70f6d-1361-fa30-01c5-0736a1826aba.png">
AI自動運転ラジコンカープロト (3-1 JetPackのインストール)

# はじめに
JetPackのインストール方法に関する記事はたくさんあるので、手順をざっと確認したい方のみ対象です。
USB-Cはどっち側だったけかな、リカバリモードはどうやるんだっけかな、にお答えします(主に自分向け)。

# 前提
- JetPack 4.2
- Jetson AGX Xavier
- [rootonNVMe](https://github.com/jetsonhacks/rootOnNVMe)

# インストール

1. NVIDIA SDK Managerをダウンロード＆インストール（ユーザ登録が必要）。
2. ヘッドピン側のUSB-CコネクタとホストPCを接続し、本体中央ボタンを押しながらオン。
3. Target Hardware/Target Operating Systemを選択してCONTINUE。
4. インストールが終わったら、SSDをGPT/EXT4でフォーマット。
5. https://github.com/jetsonhacks/rootOnNVMe のREADME.mdに従う。
Ruby:findメソッドとfind_byメソッドはどう違うのか

※2022年から技術系の記事は[個人ブログ](https://yamaday0u.net/category/programmer/)に投稿しております。ぜひこちらもご覧ください→[yamaday0u Blog](https://yamaday0u.net/category/programmer/)

プログラミングスクールの課題アプリ開発の過程で、findメソッドとfind_byメソッドを勘違いしてまる1日エラーに悩まされた経験から、findメソッドとfind_byメソッドについて整理します。

## findメソッド
IDを指定してレコードを取得します。
指定したIDの中に存在しないIDが1つでもあると例外（エラー）が発生します。

```rb
Fruit.find(1)
# 複数のIDを指定して、該当するレコードを取得できる
Fruit.find(1,4,6)
# 配列でも指定できる
Fruit.find([1,4,6])
# 同一ファイル内にidの情報を含むインスタンスがあれば、以下のような書き方ができる
Fruit.find(@fruit.id)
```

## find_byメソッド
条件を指定してヒットした最初の1件を取得します。IDも条件に指定できます。
条件にヒットするレコードが存在しない場合はnilを返します。

```rb
Fruit.find_by(name: "strawberry")
```

Fruitsテーブルに以下のようにデータが入っているとします。

```md
Fruitsテーブル
| id | name       | color  |
| 1  | apple      | red    |
| 2  | strawberry | red    |
| 3  | orange     | orange |
| 4  | banana     | yellow |
```
この場合、次のように記述して該当するデータを取得できます。

```rb
Fruit.find_by(name: "apple")
Fruit.find_by(name: "orange")
Fruit.find_by(color: "yellow")
```

個人的なミス経験で恐縮ですが、ぼくはfindメソッドとfind_byメソッドを混同して以下のように記述してエラーに悩まされていました。

```rb
Fruit.find(id: @fruit.id)
```
findメソッドを使っているのに、カッコ()の中はfind_byメソッドの文法で記述していました。


## どう違うのか
[Railsドキュメント](https://railsdoc.com/model)を読んでみると、findメソッドはRailsのバージョン1.0.0から、find_byメソッドはRailsのバージョン4.0.2から適用されているので、歴史的にはfind_byメソッドの方が後から登場したメソッドのようです。

機能的には次のような違いがあります。

+ findメソッドもfind_byメソッドもIDを指定してレコードを取得することができる
+ findメソッドはIDを複数指定していれば複数の値を取得できるが、find_byメソッドは1つのレコードしか取得できない
+ find_byメソッドはID以外の条件を指定してレコードを取得できる

結論としては、こんな感じでしょうか。

| 取得したいレコード | 使用するメソッド |
| :-- | :-- |
| 1つ&IDを指定 | findメソッド・find_byメソッド |
| 複数&IDを指定 | findメソッドのみ |
| 1つ&ID以外を指定 | find_byメソッドのみ |
| 複数&ID以外を指定 | ??? |

最後のパターンで???が出ました。
このパターンは、findメソッドでもfind_byメソッドでも取得できません。
このときはどうすればよいでしょうか？

## Whereメソッド
取得したいレコードが「複数&ID以外を指定」の場合はWhereメソッドを使用することで実行可能です。

whereメソッドは条件に当てはまる値を全て取得します。

```rb
@fruit = Fruit.where(name: "strawberry")
```

ここまでみるとwhereメソッドがなんでもできて最強じゃないかとも思いますが、findとfind_byメソッドにはできて、whereメソッドにはできないことがあります。

```rb
# findとfind_byメソッドで取得した値は、特定のカラムを取得できる
@fruit = Fruit.find(1) # もしくは、@fruit = Fruit.find_by(name: "strawberry")
@fruit.name
# 実行結果 => "strawberry"

# whereメソッドで取得した値は特定のカラムを取得できない
@fruit = Fruit.where(name: "strawberry")
@fruit.name
# 実行結果 => NoMethodErrorになる
```
findメソッドとfind_byメソッドは**モデルのインスタンスを返す**のに対し、whereメソッドは**範囲をしぼるだけ**なので、インスタンスがありません。

そこで以下のような方法で、範囲を絞った中でどれを使うか指定することで特定のカラムを取得できるようになります。

```rb
@fruit = Fruit.where(name: "strawberry").first(1)
@fruit.name
# 実行結果 => "strawberry"

@fruit = Fruit.where(name: "strawberry").take(1)
@fruit.name
# 実行結果 => "strawberry"

@fruit = Fruit.where(name: "strawberry")
@fruit.each do |fruit|
 fruit.name
end
# 実行結果 => "strawberry"
```

## 参考資料
[Railsドキュメント モデルについて](https://railsdoc.com/model)
[Qiita【Rails初心者必見！】ひたすら丁寧にデータ取得を説明(find, where)](https://qiita.com/mr-myself/items/cfb936dcf63d2c44d2f5#%E8%A3%9C%E8%B6%B3find%E3%81%A8find_by%E3%81%AE%E9%81%95%E3%81%84)
[Qiita【Rails】findとfind_byの違い](https://qiita.com/morikuma709/items/6b3b342bb19d326ad1ee)
[Qiita【Rails】find・find_by・whereについてまとめてみた](https://qiita.com/nakayuu07/items/3d5e2f8784b6f18186f2)
中華製スマートプラグ をAPIで操作する。(tuya-cli利用の代替案）

plageoj さんの記事 [新版・中華製スマートプラグを node で制御する](https://qiita.com/plageoj/items/dd2f1c8b55c39625d550)を参考に中華製のsmartplugで各プラグの電力使用量を　zabbix で管理したかったのですが　
データ取得に必要な local_keyの取得方法が他で記載の、
tuyapi/cli の `tuya-cli wizard` でうまく いかないケースがあったので代替案を紹介します。

#アプリにスマートコンセントを登録
[smart life] (ttps://apps.apple.com/us/app/smart-life-smart-living/id1115101477)　や　[tuya app](https://play.google.com/store/apps/details?id=com.tuya.smart&hl=ja&gl=US) 等の　tuya 関係の　アプリで　スマートコンセントを登録しておいてください。

#Tuya サイトアカウント登録～デバイス登録
基本は　[plageoj さんの記事] (https://qiita.com/plageoj/items/dd2f1c8b55c39625d550)の通りなのですがサイトの見た目が変わっているので記載します。

##アカウント作成
https://iot.tuya.com/ にアクセスして、アカウント作成

##プロジェクト作成
###右のCloudからProjectsを選択
![Project.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361560/262c4742-40d2-33aa-d0ae-9cdc3010f704.png)

###createを選択
![Project-Create.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361560/81d0e618-742f-4e59-fb83-d20d93a9349f.png)

###以下を入力しCreate

+ Project Name: 任意のプロジェクト名を入力
+ Description ： 説明を入力(最低20文字必要)
+ Industory   ：　任意だと思いますが私はSmart Homeを選択しました。
![Project-Create-Detail.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361560/5f0ee9be-578e-0e4d-77a8-dc42db484371.png)

##アプリからデバイス情報連携
事前に登録してあるアプリ情報を連携します。
cloud -> Link Device -> Link devices by App Account から　Add App Accountを押下し、 表示されるQRコードをアプリで読み込んで登録してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361560/f1de05e6-0a5a-a1c5-4193-6629b8459ff6.png)

問題がなければ以下のような表示になり登録されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361560/25de1a74-5734-7c23-bd19-0e0b070cf19b.png)

#Device IDの取得
　以下の Cloud-> Device List　から　APP ID/地域を選択して　DeviceのListが出るので 操作したいコンセントの device_id を控えておく
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361560/f91b6f60-c694-511b-1513-c25a7323ede3.png)

#Device Local Keyの取得

Cloud-> Get device details から　device_idを入力し Submit Requestをすることで
対応するlocal_keyの取得が可能になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/361560/388a6241-db9f-bf8a-2420-e6780a399502.png)

#まとめ
上記手順でアプリと [tuyaのサイト](https://iot.tuya.com/)から
スマートコンセントの操作に必要な 

+ コンセントのdevice_id
+ コンセントのlocal_key

を取得できました、実際の使い方等はほかの方の記事を見ていただければ。。。
業務で初めて知ったSQL関数【Oracle】

2020年9月にSESに入社し、12月から現場に出て2ヶ月目の新人です。

SQLは今まで「スッキリわかるSQL入門」などで基礎の基礎は学んできましたが、
このたび500行を超えるSQL文を読むことになり、Oracleが初めてなのもあって
初めて知ったSQL関数がありましたので備忘録として書いていこうと思います。

## ROW_NUMBER
SELECT文の結果に対して、１〜の連番を振ります。

```
-- 構文
ROW_NUMBER() OVER (
PARTITION BY カラム名, カラム名, ... ORDER BY カラム名, カラム名, ...)
```

### PARTITION BY
GROUP BYのような感じで、集計したいカラム名を指定します。


## DECODE
カラムの値によって条件分岐させて値を変換できます。

```
-- 構文
SELECT 
 DECODE(カラム名, 値1, 結果1, 値2, 結果2, 結果3)
FROM テーブル名;

-- 値1だったら結果1、値2だったら結果2、それ以外は結果3
```

CASE式でも書けます。
DECODEは条件に比較演算子や式を使えませんが、CASE式では使えます。

```
CASE カラム名
    WHEN 値1 THEN 結果1 
    WHEN 値2 THEN 結果2
    ELSE 結果3
END
```


## SUBSTR
文字列を指定桁数から指定文字数分切り取ります。

```
-- 構文
SUBSTR(文字列, 開始桁, 切り取り文字数)
```


## NVL
値がNULLだったら、別の値に変換できます。

```
-- 構文
SELECT
 NVL(カラム名, 変換したい値)
FROM テーブル名;
```

## TO_CHAR
数値や日時を文字列に変換します。

```
TO_CHAR(日付)
TO_CHAR(日付, 'YYYYMMDD(指定したい書式)')
```

## WITH
副問い合わせに名前をつけます。
以降、その名前だけで副問い合わせを使用できます。

```
WITH '名前' AS (副問い合わせ)
```

## さいごに
例文や実行結果も書こうかと思ったのですが、いい例が思い浮かばなかったので、
とりあえず構文だけ書かせてもらいました。
私が読んでいたSQL文ではDECODEが入れ子になっていたり、
SUBSTRも組み合わさっていたり、「？？」という感じでした。
徐々に読めるようになっていきたいと思います。

＜追記＞
・2021/03/27、TO_CHAR、WITH

## 参考
[Oracle初心者でもスッキリわかる](https://sql-oracle.com/)
[SHIFT the Oracle](https://www.shift-the-oracle.com/)
BeautifulSoup,Selenium備忘録

##はじめに##

スクレイピングの基本操作を備忘録用として投稿します。

##対象ページ、クラスのスクレイピング

```ruby:qiita.rb

import sys
from selenium import webdriver
import os
from bs4 import BeautifulSoup


options = webdriver.ChromeOptions()
options.add_argument('--headless')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
browser = webdriver.Chrome('chromedriver',options=options) 
# 対象のWebページURLを宣言します 
url = "https://qiita.com/" 
# 対象URLを取得 
browser.get(url)
html = browser.page_source.encode('utf-8')
soup = BeautifulSoup(html,'html.parser')
list = soup.find_all(class_ = "css-1laxd2k")

print(list)
```

結論こちらに対象URLと取得したいクラスやidをいれたら取得できる。
本来requests.get()で取得した方が楽ですけどね。

##BeautifulSoupとは##
requestsなどによってHTMLのデータをスクレイピングした後に
そのHTMLを整形するために使用。
所謂BeautifulSoupだけではスクレイピングはできない。
これ使えばスクレイピングしたデータに色々できる

##Seleniumとは##
Webページの自動化を行うためのフレームワーク
今回はoptionに色々やっているのでclickなどによるページ遷移も
すぐできたり
何回もこのコンピュータを信頼しますかと表示されて実機テストができない

#バージョン
- macOS Catalina v10.15.7
- Xcode v12.3
- iOS 14.3

#現象
xcodeで実機テストをしようと思い、iphoneをmacに接続したら、
このコンピュータを信頼しますかという画面が表示されては消えを繰り返して、
接続ができない

#解決策
lightningケーブルを交換したところ解決しました

元のケーブルも純正で充電は問題なくできたのですが、
なぜかxcodeとの接続はうまくできませんでした
Djangoをとりあえず動かす　～pythonインストールからstartprojectまで～

# どんな記事？
- Djangoの環境構築手順書を毎回忘れるので、自分用メモとして作成。
- 環境構築が完了した状態から遡って手順を確認したので、抜け漏れがあるかも。

# 環境構築手順
## python　インストール
何はともあれpythonのインストール。
（参照｜https://www.python.jp/install/windows/install.html）

今回はubuntsu経由？でインストールしたので、下コマンドを実行。
```sudo apt-get　install python3
```

## pip　インストール
pipのインストール。
（参照｜https://qiita.com/suzuki_y/items/3261ffa9b67410803443）

ubuntsuでpipをインストールする前には、ubuntsuの付属パッケージ？の更新をしておいた方が良いらしい。
```sudo apt-get update```

pipインストールは以下。
```sudo apt-get install python3-pip```


## 仮想環境構築
必須ではないが、設定しておくと何かと便利。
個人開発では必要ないかもしれないが、製品開発では動作環境が問題になることがあるので必須だと思う。
（参考｜https://www.acrovision.jp/career/?p=2254）


今回はvenvで仮想環境を構築した。
（参考｜https://qiita.com/fiftystorm36/items/b2fd47cf32c7694adc2e ）

## Django　インストール
pipでDjangoのライブラリをインストールするだけでOK。
注意点として、作成した仮想環境のディレクトリを覗いている状態でインストールする。
```pip3 install django```

## プロジェクト作成
プロジェクトを作成したいディレクトリへ移動する。

プロジェクトを作成するコマンドは以下。
```django-admin startproject [プロジェクト名]```

## プロジェクトの作成を確認
Djangoのプロジェクトは、初期状態でもアクセスできるページが存在する。
サーバーを起動して、指定されたURLにアクセスする。
```python3 manage.py runserver```

# つまづいたところ
## adminページへのアクセス不可 
**問題**
初期状態では、アクセスできていたadminページに対して、ある段階から以下のようなメッセージが出てアクセス不可になった。

エラーメッセージ：「no such table: django_session」

**原因**
viewに新たなメソッドを作成したが、DBに登録されていなかった

**対策**
migrationする
``
python manage.py makemigrations 
python manage.py migrate
``
テスト27

```vb

Private Sub Workbook_Open()

'営業日判定
'--------------------
'事前に参照設定を行う
'Microsoft XML, v3.0
'---------------------
'https://www.apibank.jp/ApiBank/api/detail?api_no=599&api_type=Iを参照
'http://s-proj.com/utils/holiday.htmlを参照
'祝日判定WebAPI
'内閣府のwebを元に祝日チェック(日本特有の官公庁や東証の休日にも対応)を行うwebAPI
'gov:官公庁（12/29-1/3が休み）
'-----------------------

Dim D As Variant
Dim apiUrL() As Variant

On Error GoTo ErExit

ReDim Preserve apiUrL(1 To 3)

Application.ScreenUpdating = False

'無色
ThisWorkbook.Sheets("Sheet7").Range("B4:B7").Interior.ColorIndex = 0
D = Replace(Date, "/", "")
'"http://s-proj.com/utils/getBusinessDay.php?kind=next5&date_format=yyyy/mm/dd&date=" &　D　& "opt=gov"
apiUrL(1) = "http://s-proj.com/utils/getBusinessDay.php?kind=next&date_format=yyyy/mm/dd&date=" & D & "&opt=gov"
apiUrL(2) = "http://s-proj.com/utils/getBusinessDay.php?kind=next5&date_format=yyyy/mm/dd&date=" & D & "&opt=gov"
apiUrL(3) = "http://s-proj.com/utils/getBusinessDay.php?kind=next10&date_format=yyyy/mm/dd&date=" & D & "&opt=gov"

Set HttpReq = CreateObject("MSXML2.XMLHTTP")

For i = 1 To 3

    HttpReq.Open "GET", apiUrL(i), False
    
    HttpReq.Send (Null)
    
    ThisWorkbook.Sheets("Sheet7").Cells(i + 3, 2).Value = HttpReq.responseText

Next i

D = Date + 21

ThisWorkbook.Sheets("Sheet7").Cells(7, 2).Value = D

Application.ScreenUpdating = True

Exit Sub

'----------------------
ErExit:

'削除
ThisWorkbook.Sheets("Sheet7").Range("B4:B7").ClearContents

'黄色
ThisWorkbook.Sheets("Sheet7").Range("B4:B7").Interior.ColorIndex = 27

MsgBox "サーバーに接続できなかったので、手入力でお願いします。", vbCritical

Set HttpReq = Nothing

Application.ScreenUpdating = True

End Sub

```
GitHub有償プラン(Pro)の申込方法

# はじめに
GitHubも無償でできることが拡がってきており、以前と違って有償プラン(GitHub Pro)を利用する動機付けが乏しいのかも知れませんが、ここでは、FreeプランからProプランへの移行申込方法についてご紹介します。入力等、画面を見ればあまりにも自明だからなのか、Qiitaでも類似した記事を見つけられなかったので、書いてみました。

なお、そもそもGitHubにアカウントを持っていない、ということであれば、以前書いたこちらの記事をご覧くださいませ。

- [GitHubにサインアップ(Sign up) - 新規ユーザ登録](https://qiita.com/mfunaki/items/e01762475967d4e05a1f)

# FreeプランとProプランの違い
移行手続きに入る前に、FreeプランとProプランでできることにどの程度違いがあるのでしょうか？詳しくは、[Pricing](https://github.com/pricing)のページをご覧いただくのが...と思ったら、こちらには、Free / Team / Enterprise / GitHub One の比較表はあるのですが、Proプランは紹介されていないようです。Proプラン申込手順の中で、あらためてご紹介しましょう。

# Proプラン申込手順
## 自アカウントにログイン、加入中プランを確認

[GitHub](https://github.com)にアクセスし、自分のアカウントにログインします。

右上のアイコン(自分の顔写真だったりイニシャルだったり)をクリックし、表示されるメニューからUpgradeをクリックします。

![Upgrade](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/470dc4d5-4859-801e-befa-cd7ff4ee317e.png)

## アップグレードプランの内容・費用確認

FreeプランとProプランの比較(結構長い)、ならびに費用が表示されていますので、確認の上、`Upgrade to Pro`ボタンをクリックします(すると、より簡潔なProプラン提供機能が紹介されます)。

![Compare plans](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/b6a17168-62af-de43-8acb-5a2735b61de5.png)

## アップグレードプランの内容・費用の再確認と、支払方法の入力

さて、`Upgrade to Pro`ボタンをクリックすると、まずは、GitHub Proプランの内容として、
- GitHub Freeプランで提供される内容 プラス
- Privateリポジトリでのレビュー(変更承認)を必須に設定可
- Privateリポジトリでのブランチ保護を設定可
- Privateリポジトリでのリポジトリインサイトを確認可
- PrivateリポジトリでのWiki利用可
- PrivateリポジトリでのGitHub Pagesの利用可
- Privateリポジトリでのコードオーナーの指定可
- GitHub Actionsを3000分 利用可
- GitHubパッケージ用のストレージを2GB 利用可

が挙げられています(2021/01/23現在)。また、費用は月払い(Pay monthly)であれば月額 4.00米ドル、年払い(Pay yearly)であれば年額 48.00米ドルということで、特に割引の設定はない模様です(2021/01/23現在)。

支払いはクレジットカード、またはPayPalで行うことができます。必要な情報を入力したら`Submit`ボタンを押します。

![Upgrade from GitHub Free to GitHub Pro](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/8069da79-c9d1-04e0-0ef7-eb8a261df08f.png)

## アップグレード、および支払内容の確認

`Submit`ボタンを押すと、確認画面が表示されますので、確認の上、問題がないようであれば、`Upgrade my account`ボタンをクリックします。

![Screenshot from 2021-01-23 22-08-50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/124ec1fc-9311-1e23-6324-2b68de48ed7d.png)

## アップグレード完了

`Upgrade my account`ボタンをクリックすると、Current Plan(現在加入中のプラン)としてGitHub Proの内容と費用、および、各種サービスの当月の利用状況が表示されます。

![Screenshot from 2021-01-23 22-09-19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/19248/2049e502-15dc-ac86-3967-ce425d3acc6f.png)

# おわりに
GitHubの場合、Publicなリポジトリでできたあんな事やこんな事がPrivateリポジトリでもできるようになる、というのが大きな違いになりますね。それでは！
VMを使ったプロキシ環境の構築

# はじめに
* プロキシ環境での動作確認をしたい時に、VMを使ってプロキシ環境を再現することができます。
* 本記事では、プロキシ環境の構築方法を記載します。
* 下記のようなネットワーク構成とします。

![network.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251754/3d27db8f-4136-6e5a-4823-9fa968f917d2.png)

### 作業環境
* VirtualBox 6.1.14 r140239
* Squid for Windows 3.5.28

# 構築手順
### VirtualBoxのホストネットワークの設定
1. VirtualBoxでホストネットワークの設定を開く。
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251754/d10f518c-b05b-07c9-c0d2-2c3745570b0a.png)

1. アダプターを作成し、IPアドレスを割り当てる(既に作成されている場合は省略)。
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251754/44bef96d-0e96-26fa-d2d6-2e5dfffa24c2.png)

### ゲストOSのネットワーク設定
1. ゲストOSのネットワーク設定を「ホストオンリーアダプター」にし、先程作成したアダプターを割り当てる。
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251754/01b64294-48ec-cf27-5cca-2777d508dc64.png)

### プロキシサーバーの構築
1. ホストOSにSquid for Windowsをインストールする。
 * https://squid.diladele.com/
1. basic認証の設定をする(オプション)。
    * 認証に使うパスワードを生成する。
        * https://www.luft.co.jp/cgi/htpasswd.php
    * 生成したパスワードをファイルに貼り付けて、以下のパスに配置する。
        * 本記事ではファイル名をpasswdとする。
        * c:/squid/etc/squid/passwd
    * 設定ファイルsquid.confを開く。
<div align="center">
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251754/c78ea620-1788-3657-c50b-759d31c60195.png)
</div>
    * 以下を追記し、サービスを再起動する。


```conf:squid.conf

#許可するサブネット
acl [規則名] src 192.168.1.0/24

#ACL[規則名]をパスすればアクセスを許可する
http_access allow [規則名]

#コメントアウト
#http_access allow localnet
#http_access allow localhost

#basic認証を要求する際は以下も追記

#ルール「hoge」を認証必須のACLとする
acl hoge proxy_auth REQUIRED

auth_param basic program  c:/squid/lib/squid/basic_ncsa_auth.exe  c:/squid/etc/squid/passwd

#同時にsquidを使用できるクライアント数
auth_param basic children 5

#basic認証時にクライアントに表示されるタイトル
auth_param basic realm Squid proxy-caching web server

#認証した際の有効な時間
auth_param basic credentialsttl 2 hours

#ID/PASSの大文字小文字を区別しない
auth_param basic casesensitive off


```
### ゲストOSのプロキシ設定
1. ゲストOSのネットワークプロパティを開く。
![5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251754/6607ae36-3a0e-d255-1025-94f17229c757.png)
1. IPアドレスを設定する。
<div align="center">
![6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251754/78f0ff98-2e39-73df-6f87-6961411b7328.png)
</div>
1. インターネットオプションからプロキシサーバーを指定する。
<div align="center">
![7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251754/0ec2d772-a829-aa94-7fa2-028e6fb27d45.png)
</div>

**完成**
# 参考
* http://www.squid-cache.org/
Railsアプリのための環境構築

#構築済の環境
+ Homebrewのインストール
+ rbnevのインストール
+ Rubyのインストール（2.7.2）
+ node.jsのインストール

#RubyGemsのアップデート
Rubyのサードパーティライブラリの利用で、プログラミングが楽になるようです。
これらは「gem」という形式で配布されています。
「RubyGems」というパッケージ管理ツールはRubyインストール時に同梱されるようです。

最新版へのアップデートは以下のコマンド。

```
$ gem update --system
```


#Bundlerのインストール
開発現場では、gemの管理が重要になってきます。
そこで登場するのが「Bundler」プロジェクトで用いるgemをまとめ、互換性を保ちながらパッケージの種類やバージョンを管理してくれます。
プロジェクトのディレクトリに「Gemfile」というファイルを作成し,gemの名前を記載しておくと、うまくやってくれます。

以下のコマンドでインストール

```
$gem install bundler
```

今後はBundler経由でgemに関する操作をすることで、メンバーとの環境を同様にすることができます。
（gemコマンドで直接操作してしまうと、Bundlerの管理環境から逸脱してしまうようです）

#データベース（MySQL）のインストール
今回はMySQlを利用します。

```
brew install mysql
```

インストール後、起動させます。

```
mysql.server start
```

（以下でもOK？）

```
brew services start mysql@バージョン
```

「SUCCESS」と表示されれば起動完了です。

#データベース（MySQL）のインストール
今回はMySQlを利用します。

```
brew install mysql
```

インストール後、起動させます。

```
mysql.server start
```

（以下でもOK？）

```
brew services start mysql@バージョン
```

「SUCCESS」と表示されれば起動完了です。

##MySQLの初期設定
起動状態で以下のコマンド入力をして、初期設定をおこないます。

```
mysql_secure_installation
```
いくつか設定項目が続きます。順番は以下の通りです。

1.パスワード設定を行うか問われるのでyを入力。

2.パスワードの強度を設定。練習なので「0」のLowを選択。

3.パスワードを2回入力し、設定完了。

4.「匿名ユーザー」を削除するかの質問。これはMySQLをインストールした際に自動で作成されるユーザーアカウントで、パスワード不要でMySQLに接続することが可能。
セキュリテイ上のリスクがあるためyを入力。

5.「root」ユーザー（初期設定）へのログインをリモートサーバーから可能にするかの確認。
同様にセキュリテイ上のリスク回避のためyを入力。

6.デフォルトのテストデータベースを削除するかの確認。使用しないのでyを入力。

7.これまでの設定内容を即時にデータベースに反映するかの確認。yを入力。

これで設定は完了です。

##MySQLへのログイン・ログアウト・停止
設定したパスワードでログインします。

```
mysql -uroot -p
```

ログアウトは、

```
exit;
```

「Bye」と表示されればログアウト完了です。

MySQL自体の停止は、

```
brew services stop mysql@バージョン名
```

「Successfully stopped msyql@」と表示されれば停止完了です。


ここまで、環境構築は終了です。長かった…
次回はRailsアプリの新規作成までを記事にしていきます。

#参考
+ [現場で使える Ruby on Rails 5速習実践ガイド](https://www.amazon.co.jp/gp/product/B07JHQ9B5T/ref=ppx_yo_dt_b_d_asin_title_o03?ie=UTF8&psc=1)
+ [Mac環境にMySQLをインストールしてみよう！初期設定までの手順を徹底解説！](https://style.potepan.com/articles/19020.html)
+ [MySQLの開発環境を用意しよう（macOS）](https://prog-8.com/docs/mysql-env)
rails　検索機能の実装

# 1.ルーティングの指定

ルーティングの中に検索したいテーブルの中にserchを記述します。以下を例とします。collectionを使うことによって生成されるルーティングのURLと実行されるコントローラーを任意でカスタムできます。

```ruby:config/routes.rb
resources :posts do
      collection do
        get 'search'
      end
  end
```
# 2.モデルの指定
モデルを指定します。以下のようにwhereメソッドとLIKE句を使い、検索をかけたいカラムを記述します。


```ruby:post.rb
def self.search(search)
        if search != ""
          Post.where('text LIKE(?)', "%#{search}%" )
        else
          Post.all
        end
      end
```
# 3.この他に検索のカラムを追加したいとき
もしいくつかのカラムを検索につかしたいときは、orを使い"%#{search}%"以下のように記述しましょう。

```ruby:post.rb
def self.search(search)
        if search != ""
          Post.where('text LIKE(?) or title LIKE(?)', "%#{search}%", "%#{search}%")
        else
          Post.all
        end
      end
```

#4 コントローラーにserchアクションを記述
コントローラーにsearchアクション記述をします。この記述でバックエンドの記述は終了です。あとはビューに反映させるだけなので、お好みの形でデザインしましょう。

```ruby:controllers/posts_controller.rb
def search
 @post = Post.search(params[:keyword])
end
```

# 5.最後に
検索機能自体は他のアクションと同じように設定できますので、モデルの指定だけ特徴をつかめば簡単に実装できます。是非実装してみましょう。