アウトプットの部屋

エンジニアになるためのアウトプット

N+1問題とは??

userは複数のpostsをもつ 「user has_many posts」などの関係で、postsを取得する際にpostsの数だけSQLクエリが発行されること。

対策

includesを使う!

モデル名.includes(:関連名)

*関連名はテーブル名ではない

例えば上記の例では

@posts = Post.all.includes(:user)

となる。

n:1:nの場合

userがcommentを持っている時

user has_many posts user has_many comments

comment belongs_to user

@posts = Post.all.includes(user: :comments)

となる。

ちなみにbulletというgemを使うことで開発時に自動でN+1を検知してくれる!

Rust③ 数字当てゲーム2

match式

use std::cmp::Ordering;

match guess.cmp(&secret_number) {
        Ordering::Less => println!("Too small!"),  
        Ordering::Greater => println!("Too big!"), 
        Ordering::Equal => println!("You win!"),    
    }

cmpメソッドはguess変数とsecret_number変数を比較し、返ってきたOrderringの列挙子に基づき動作する。

例 guess = 50 secret_number = 30の時、cmpメソッドは Ordering::Greaterを返し、 Ordering::Lessから一行ずつ順番にマッチするものを探し、マッチしたら=>のコードが動作する。

let guess: u32 = match guess.trim().parse() {
    Ok(num) => num,
    Err(_) => continue,
};

u32は32ビットの非負整数。

trimは両端の空白を削除するString型のメソッド。

parseメソッドは文字列から数値に変換できた時、Okを返す。Okの場合、一行目のOk(num)にマッチし、=>のnumを返す。 その値が新しく生成したguessに格納される。

そうでない場合、Err(_)にマッチする。この_は、包括値で、この例では保持している情報がどんなものでもいいから全てのErr値にマッチさせたいと言う意味。coutinueはループ処理の次のステップに移すコード。

loop 繰り返し

loop {
        println!("Please input your guess.");

        // --snip--

        match guess.cmp(&secret_number) {
            Ordering::Less => println!("Too small!"),
            Ordering::Greater => println!("Too big!"),
            Ordering::Equal => { 
                 println!("You win!"),
                 break;
            }
        }

    }

breakでループから抜け出せる。

Rust② 数字当てゲーム1

main.js

use std::io;

fn main() {
    println!("Guess the number!"); 

    println!("Please input your guess.");

    let mut guess = String::new();

    io::stdin().read_line(&mut guess)
        .expect("Failed to read line");

    println!("You guessed: {}", guess);
}

let は変数を宣言する。mutはmutableの意味で変数の値を変更できる。

//はコメント(日本語はコンパイル失敗する可能性がある)

let mut bar = 5; // mutable

文字列型のオブジェクトを作成

String::new();

「::」はnewがString型の関連関数であることを表している。 関連関数とは、String型の特定のオブジェクトよりも型(この場合はString)に対して 実装された関数のことであり、静的(スタティック)メソッドと呼ばれる言語もある。

簡単に言えば、「空のString型のオブジェクトを生成する」という意味。

io::stdin().read_line(&mut guess)
    .expect("Failed to read line");

io::stdin()はユーザーの入力を受け付ける(use std::io;が必要)

read_line(&mut guess) read_lineメソッドは、ユーザが標準入力したものすべてを取り出し、文字列に格納することなので、 格納する文字列を引数として取る。 引数は可変である必要があるため、guessではなく&mutをつける。

読み込みに失敗したらexpectが呼び出される。

{}の使い方

let x = 5;
let y = 10;

println!("x = {} and y = {}", x, y);
=>x = 5 and y = 10

Rustチュートリアル①

Rustとは・・・「安全性、速度、並行性」の3つに焦点をあわせたコンパイル言語(静的プログラミング言語)。C++の特徴でもあった高速性を維持しながら安全なメモリ管理が用意に可能。Firefoxでも採用されている

インストールにはrustupというツールを使うだけなので非常に簡単。

rustupのインストール

$ curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh

これだけでRustをインストールできる。

cargoとは・・・Rustのビルドシステム兼パッケージマネージャ。cargoを使いRustを管理する。

cargo new hello_cargo --bin

これでhello_cargoディレクトリが作成される。予め空のディレクトリに移動して叩くとそのディレクトリの中に作られる。

cargo build

でプロジェクトをビルドする。(cargo checkでもok)

cargo run

でプロジェクトのビルドと実行を1ステップでできる。

またビルドの結果をコードと同じディレクトリに保存するのではなく、cargoはtarget/debugディレクトリに格納する。

RSpec③~skipやpending~

テストの量が多くなると、RSpecの起動時間が長くなってしまう。ファイル名を指示して実行すれば多少速くなるが、そのファイル自体が重いとそれでも時間がかかってしまう。そのような時に使えるものがいくつかある。

1 pending

it ~~~~~  do
  pending  'あとで見直す'
end

このように書く。pendingはテストを中断するのではなくそのまま実行する。

テストが失敗していると「pending(保留)」としてマークされ、最後までテストがパスした場合は pending にならずRSpecに怒られて失敗になる。

2 skip

it ~~~~~  do
  skip  'とりあえずここから先は実行しない'
end

skipはそこから先は実行せずpendingとしてマークする。

3 xit

itをxitにするとその全体のexampleがpendingとしてマークされる。同じようにxdescribeやxcontextも使える。

RSpec②~supportファイルの設定~

supportファイルの作成や設定のメモ

1 ファイル作成

mkdir spec/support
touch spec/support/request_helper.rb

2 rails_helper.rbを編集 以下の行をコメントインする

Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }

eachメソッドでsupportディレクトリ配下のファイルを1つずつ読みこむ。

さらにconfigの配下に記入

config.include RequestHelper

これで各ファイルにincludeされるようになる

Dockerメモ①~attachとexec~

コンテナを起動する時は、

docker start [コンテナ名]

で行う。停止する時はstopコマンド。runやcompose-upをするとコンテナが増えてしまう。

コンテナをstartで起動すると、サーバーログが見えなくなる。そんな時には、

docker attach [コンテナ名]

でサーバーログが見れるようになる。ただしそのログから抜けると、コンテナも停止する。

attachとexecの違い

attachはコンテナ内でシェルが起動して無ければ接続できない。exitコマンドで抜けると、コンテナも停止する。

execはコンテナ内でシェルが起動してなくても接続できる(稼働コンテナでPID=1のプロセスを実行するため)。exitコマンドで抜けても、コンテナが停止しない。execの接続の仕方は、

docker exec -it コンテナ名 /bin/bash

iオプション・・・標準入力(STDIN)を開いたままにする

tオプション・・・擬似ttyに接続する。ディスプレイ(STDOUT)をつなぐイメージ

(標準入力・出力とは、コマンド/アプリ側で入力元・出力先を明示することなく使用できる入力) (ttyとは、標準出力の接続先デバイスのこと)