Rustでよく使う標準トレイト一覧:Display・Debug・Clone・Iteratorなど

Rustでよく使う標準トレイト一覧:Display・Debug・Clone・Iteratorなど

はじめに

Rustの標準ライブラリには多くのトレイトが用意されています。コードを書いていると #[derive(Debug)]impl Display for といった記述を頻繁に見かけます。

この記事ではよく使う標準トレイトを用途別にまとめます。トレイトの基本的な書き方は「Rustのトレイト入門:実装方法を基礎から解説」を参照してください。


表示・デバッグ系

Debug

デバッグ用の出力({:?})を有効にします。ほぼすべての型で derive できます。

#[derive(Debug)]
struct Point {
    x: i32,
    y: i32,
}

let p = Point { x: 1, y: 2 };
println!("{:?}", p);   // Point { x: 1, y: 2 }
println!("{:#?}", p);  // 整形表示

Display

ユーザー向けの出力({})を有効にします。derive は使えないので手動で実装します。

use std::fmt;

struct Point {
    x: i32,
    y: i32,
}

impl fmt::Display for Point {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

let p = Point { x: 1, y: 2 };
println!("{}", p);  // (1, 2)

コピー・クローン系

Clone

値を明示的に複製します。clone() メソッドを呼び出すことで複製できます。

#[derive(Clone, Debug)]
struct Config {
    name: String,
}

let a = Config { name: "config".to_string() };
let b = a.clone();
println!("{:?}", b);  // Config { name: "config" }

Copy

代入時に自動的にコピーされます(clone() 不要)。スタックに乗る小さな型に使います。

#[derive(Copy, Clone, Debug)]
struct Point {
    x: i32,
    y: i32,
}

let a = Point { x: 1, y: 2 };
let b = a;  // コピーされる(aも引き続き使える)
println!("{:?}", a);  // OK

StringVec のようにヒープを持つ型には Copy は実装できません。


比較系

PartialEq / Eq

==!= を使えるようにします。

#[derive(Debug, PartialEq)]
struct Point {
    x: i32,
    y: i32,
}

let a = Point { x: 1, y: 2 };
let b = Point { x: 1, y: 2 };
println!("{}", a == b);  // true

EqPartialEq の完全版(すべての値同士が比較可能なことを保証)。多くの場合は両方 derive します。

#[derive(Debug, PartialEq, Eq)]
struct Id(u32);

PartialOrd / Ord

<, >, <=, >= を使えるようにします。ソートに必要です。

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
struct Score(u32);

let mut scores = vec![Score(80), Score(60), Score(90)];
scores.sort();
println!("{:?}", scores);  // [Score(60), Score(80), Score(90)]

デフォルト値系

Default

型のデフォルト値を返します。

#[derive(Debug, Default)]
struct Config {
    width: u32,
    height: u32,
    title: String,
}

let c = Config::default();
println!("{:?}", c);  // Config { width: 0, height: 0, title: "" }

一部のフィールドだけカスタム値にしたいときに便利です。

let c = Config {
    title: "マイアプリ".to_string(),
    ..Default::default()
};

イテレータ系

Iterator

for ループや mapfilter などのメソッドを使えるようにします。next() を実装するだけで多数のメソッドが自動的に使えます。

struct Counter {
    count: u32,
    max: u32,
}

impl Iterator for Counter {
    type Item = u32;

    fn next(&mut self) -> Option<u32> {
        if self.count < self.max {
            self.count += 1;
            Some(self.count)
        } else {
            None
        }
    }
}

let counter = Counter { count: 0, max: 3 };
let v: Vec<u32> = counter.collect();
println!("{:?}", v);  // [1, 2, 3]

From / Into

型変換を定義します。From を実装すると Into が自動で使えます。

struct Wrapper(i32);

impl From<i32> for Wrapper {
    fn from(val: i32) -> Self {
        Wrapper(val)
    }
}

let w = Wrapper::from(42);
let w: Wrapper = 42.into();  // Into も自動で使える

まとめ

トレイト 用途 derive可否
Debug {:?} での出力
Display {} での出力 ❌(手動実装)
Clone .clone() で複製
Copy 代入時に自動コピー
PartialEq / Eq == / != 比較
PartialOrd / Ord 大小比較・ソート
Default デフォルト値
Iterator イテレータ操作 ❌(手動実装)
From / Into 型変換 ❌(手動実装)

Rustのトレイト入門:実装方法を基礎から解説

Rustのトレイト入門:実装方法を基礎から解説

はじめに

Rustを学んでいると trait という言葉が頻繁に出てきます。トレイトはRustの型システムの中心的な概念で、「型がどんな操作をサポートするか」を定義する仕組みです。

この記事ではトレイトの基本的な書き方と実装方法を解説します。


トレイトとは

トレイトは「メソッドのシグネチャの集まり」を定義するものです。他の言語のインターフェースに近い概念です。

trait Animal {
    fn name(&self) -> &str;
    fn sound(&self) -> &str;
}

このトレイトを実装した型は name()sound() を持つことが保証されます。


トレイトを実装する

impl トレイト名 for 型名 の形で実装します。

struct Dog;
struct Cat;

impl Animal for Dog {
    fn name(&self) -> &str {
        "犬"
    }
    fn sound(&self) -> &str {
        "ワン"
    }
}

impl Animal for Cat {
    fn name(&self) -> &str {
        "猫"
    }
    fn sound(&self) -> &str {
        "ニャー"
    }
}

実装した型は同じように使えます。

fn introduce(animal: &impl Animal) {
    println!("{}は{}と鳴きます", animal.name(), animal.sound());
}

introduce(&Dog);  // 犬はワンと鳴きます
introduce(&Cat);  // 猫はニャーと鳴きます

デフォルト実装

トレイト側にデフォルトの実装を持たせることができます。実装する型はオーバーライドしても、そのまま使ってもOKです。

trait Greet {
    fn name(&self) -> &str;

    fn hello(&self) {
        println!("こんにちは、{}です", self.name());
    }
}

struct User {
    name: String,
}

impl Greet for User {
    fn name(&self) -> &str {
        &self.name
    }
    // hello() はデフォルト実装をそのまま使う
}

let user = User { name: "太郎".to_string() };
user.hello();  // こんにちは、太郎です

トレイト境界:引数の型制約

関数の引数にトレイトを使って「このトレイトを実装している型なら何でも受け取る」という制約を書けます。

impl Trait 構文(シンプル)

fn print_name(animal: &impl Animal) {
    println!("{}", animal.name());
}

ジェネリクス + トレイト境界

fn print_name<T: Animal>(animal: &T) {
    println!("{}", animal.name());
}

複数のトレイトを要求する場合は + でつなぎます。

fn show<T: Animal + std::fmt::Debug>(animal: &T) {
    println!("{:?}", animal);
    println!("{}", animal.name());
}

where 句(複雑なときに読みやすい)

fn show<T>(animal: &T)
where
    T: Animal + std::fmt::Debug,
{
    println!("{:?}", animal);
}

戻り値にトレイトを使う

impl Trait は戻り値の型にも使えます。

fn make_animal() -> impl Animal {
    Dog
}

ただし返す型は1種類に固定されます。条件によって DogCat を返したい場合はトレイトオブジェクト(Box<dyn Animal>)を使います。

fn make_animal(is_dog: bool) -> Box<dyn Animal> {
    if is_dog {
        Box::new(Dog)
    } else {
        Box::new(Cat)
    }
}

まとめ

概念 書き方
トレイト定義 trait Name { fn method(&self); }
トレイト実装 impl Trait for Type { ... }
デフォルト実装 トレイト定義内にメソッド本体を書く
引数の制約 fn f(x: &impl Trait) / fn f<T: Trait>(x: &T)
動的ディスパッチ Box<dyn Trait>

Rustの標準ライブラリには便利なトレイトが多数用意されています。よく使うものは「Rustでよく使う標準トレイト一覧:Display・Debug・Clone・Iteratorなど」で解説しています。

Rustの配列(array)初期化まとめ:[T; N]の書き方

Rustの配列(array)初期化まとめ:[T; N]の書き方

はじめに

Rustの配列([T; N])はサイズがコンパイル時に決まる固定長のデータ構造です。スタック上に確保されるためVecより軽量ですが、サイズの扱いにRust特有のルールがあります。

この記事では配列の初期化パターンをまとめて解説します。動的にサイズが変わるVecについては「RustのVec初期化まとめ:vec!マクロからVec::newまで」を参照してください。


基本的な書き方

値を列挙して初期化する

let a: [i32; 5] = [1, 2, 3, 4, 5];
println!("{:?}", a);  // [1, 2, 3, 4, 5]

同じ値で埋める

let a = [0; 5];
println!("{:?}", a);  // [0, 0, 0, 0, 0]

let a = [true; 3];
println!("{:?}", a);  // [true, true, true]

サイズにはconst(定数)を使う

配列のサイズには変数は使えません。const か数値リテラルのみ有効です。

const SIZE: usize = 5;
let a = [0; SIZE];  // OK

let size = 5;
let a = [0; size];  // コンパイルエラー
error[E0435]: attempt to use a non-constant value in a constant

実行時にサイズが決まる場合は Vec を使います。


array::from_fn で各要素を計算して初期化する

std::array::from_fn を使うと各インデックスに対して値を計算できます。

let a: [i32; 5] = std::array::from_fn(|i| i as i32 * 2);
println!("{:?}", a);  // [0, 2, 4, 6, 8]

連番を作りたい場合:

let a: [usize; 5] = std::array::from_fn(|i| i + 1);
println!("{:?}", a);  // [1, 2, 3, 4, 5]

Defaultトレイトで初期化する

Default を実装している型は Default::default() で初期化できます。

let a: [i32; 5] = Default::default();
println!("{:?}", a);  // [0, 0, 0, 0, 0]

let a: [bool; 3] = Default::default();
println!("{:?}", a);  // [false, false, false]

let a: [String; 3] = Default::default();
println!("{:?}", a);  // ["", "", ""]

ただし Default で初期化できる配列のサイズは現在32まで(それ以上は手動実装が必要)。


多次元配列

let a: [[i32; 3]; 2] = [[0; 3]; 2];
println!("{:?}", a);  // [[0, 0, 0], [0, 0, 0]]

値を列挙する場合:

let a = [[1, 2, 3], [4, 5, 6]];
println!("{:?}", a);  // [[1, 2, 3], [4, 5, 6]]

配列とVecの使い分け

配列 [T; N] Vec Vec<T>
サイズ コンパイル時に固定 実行時に変更可能
メモリ スタック ヒープ
速度 速い やや遅い
サイズが変数 不可

サイズが決まっていてパフォーマンスを重視する場合は配列、サイズが動的に変わる場合はVecを選びます。


まとめ

方法
値を列挙 [1, 2, 3, 4, 5]
同じ値で埋める [0; 5]
インデックスから計算 std::array::from_fn(|i| i * 2)
デフォルト値 Default::default()

サイズには変数を使えない点に注意してください。実行時にサイズが決まる場合は Vec を使います。

Rails のDB操作コマンド入門:db:create から db:migrate まで

Rails のDB操作コマンド入門:db:create から db:migrate まで

はじめに

Railsを使い始めると、データベース操作のコマンドが多くて混乱することがあります。

  • db:migratedb:schema:load の違いがわからない
  • db:resetdb:migrate:reset は何が違うの?
  • マイグレーションを間違えたときどうやって戻す?

この記事では Rails のDBコマンドを用途別にまとめて解説します。


前提:Railsのデータベース設定

データベースの接続情報は config/database.yml に書かれています。

default: &default
  adapter: mysql2      # または postgresql、sqlite3
  encoding: utf8mb4
  pool: 5
  username: root
  password:
  host: localhost

development:
  <<: *default
  database: myapp_development

test:
  <<: *default
  database: myapp_test

コマンドを実行する際は RAILS_ENV によって対象のDBが変わります。デフォルトは development 環境です。


データベースを作る・消す

データベースを作成する

bin/rails db:create

config/database.yml に設定されたデータベースを作成します。developmenttest の両方が作成されます。

Created database 'myapp_development'
Created database 'myapp_test'

データベースを削除する

bin/rails db:drop

データベースごと削除します。中のデータもすべて消えます。


マイグレーションを実行する

未実行のマイグレーションをすべて実行する

bin/rails db:migrate

db/migrate/ 配下のマイグレーションファイルのうち、まだ実行されていないものを順番に実行します。

マイグレーションの状態を確認する

bin/rails db:migrate:status
Status   Migration ID    Migration Name
--------------------------------------------------
   up     20240101000001  CreateUsers
   up     20240201000001  AddEmailToUsers
  down    20240301000001  CreatePosts

up が実行済み、down が未実行です。

1つ前に戻す

bin/rails db:rollback

直前に実行したマイグレーションを1つ取り消します。

複数まとめて戻す

bin/rails db:rollback STEP=3  # 3つ分戻す

スキーマを読み込む

schema.rb からテーブルを作成する

bin/rails db:schema:load

db/schema.rb を読み込んでテーブルを一括作成します。マイグレーションを1つずつ実行するのではなく、最終的なスキーマを直接適用します。

db:migratedb:schema:load の違い

db:migrate db:schema:load
何をするか マイグレーションファイルを順番に実行 schema.rb を一括適用
使う場面 通常の開発・本番環境への反映 新しい環境のセットアップ
速さ マイグレーション数に比例 速い

新しくプロジェクトに参加してローカル環境を作るときは db:schema:load の方が速くセットアップできます。ただし既存データがある環境では使えません(テーブルが上書きされます)。


シードデータを投入する

初期データを投入する

bin/rails db:seed

db/seeds.rb に書かれた内容を実行します。開発環境の動作確認用データや、マスターデータの初期投入に使います。

# db/seeds.rb
User.create!(name: '管理者', email: 'admin@example.com', role: :admin)

まとめてやる系コマンド

DBを作成してマイグレーションも実行する

bin/rails db:create db:migrate

コマンドは && なしで並べて書けます。

DBを作成してスキーマ読み込み・シードも実行する

bin/rails db:create db:schema:load db:seed

Rails には db:setup という短縮コマンドもあります。

bin/rails db:setup

db:create + db:schema:load + db:seed を一括実行します。新しく環境を作るときの定番コマンドです。

環境によってdb:setupかdb:migrateを自動で使い分ける(Rails 6以降)

bin/rails db:prepare

DBが存在しなければ db:setup、すでに存在すれば db:migrate を実行します。CIや複数人での開発で「DBがある環境もない環境も同じコマンドで動かしたい」ときに便利です。

DBを作り直す(データが消える)

bin/rails db:reset

db:drop + db:create + db:schema:load + db:seed を一括実行します。開発中にDBを初期化したいときに使います。

マイグレーションをすべて戻して再実行する

bin/rails db:migrate:reset

db:drop + db:create + db:migrate を実行します。db:reset との違いは schema.rb ではなくマイグレーションファイルを使う点です。


よくあるシーン別まとめ

新しくプロジェクトをクローンした

bin/rails db:create db:schema:load db:seed

マイグレーションファイルを追加した

bin/rails db:migrate

マイグレーションを間違えた(直前のものを修正したい)

bin/rails db:rollback
# マイグレーションファイルを修正
bin/rails db:migrate

開発中にDBをきれいにしたい

bin/rails db:reset

まとめ

コマンド 何をするか
db:create データベースを作成する
db:drop データベースを削除する
db:migrate 未実行のマイグレーションを実行する
db:migrate:status マイグレーションの実行状態を確認する
db:rollback 直前のマイグレーションを取り消す
db:schema:load schema.rbからテーブルを一括作成する
db:seed 初期データを投入する
db:setup db:create + db:schema:load + db:seed をまとめて実行
db:prepare DBがなければdb:setup、あればdb:migrate(Rails 6以降)
db:reset DBを作り直してschema.rbとseedを再実行
db:migrate:reset DBを作り直してマイグレーションを再実行

Rubyのバージョン管理については「Rubyのバージョン管理:rbenv・miseの使い方と切り替え方法」を参照してください。

JavaScriptの正規表現入門:よく使うパターンと書き方まとめ

JavaScriptの正規表現入門:よく使うパターンと書き方まとめ

はじめに

正規表現(Regular Expression)は、文字列のパターンを表現する記法です。JavaScriptでは文字列の検索・置換・バリデーションなど、さまざまな場面で使います。

「難しそう」と敬遠されがちですが、よく使うパターンは限られています。この記事では実用的なものに絞って解説します。


正規表現の書き方

JavaScriptの正規表現は /パターン/フラグ と書きます。

const regex = /hello/;
const regex2 = new RegExp('hello');  // 同じ意味

通常はリテラル記法(/パターン/)を使います。変数を埋め込みたい場合だけ new RegExp() を使います。


基本的なメソッド

test() — マッチするか確認する

const regex = /hello/;
regex.test('hello world');  // true
regex.test('goodbye');      // false

バリデーションなど「含むかどうか」だけ知りたいときに使います。

match() — マッチした文字列を取得する

const str = 'today is 2024-05-16';
const result = str.match(/\d{4}-\d{2}-\d{2}/);
console.log(result[0]);  // '2024-05-16'

マッチしない場合は null を返します。

replace() — 置換する

const str = 'Hello World';
str.replace(/World/, 'JavaScript');  // 'Hello JavaScript'

フラグ g をつけると全件置換になります。

'aaa'.replace(/a/g, 'b');  // 'bbb'

split() — 分割する

'a,b,,c'.split(/,+/);  // ['a', 'b', 'c']

フラグ

正規表現のスラッシュの後ろにフラグをつけると動作が変わります。

フラグ 意味
g 全件マッチ(グローバル)
i 大文字・小文字を区別しない
m 複数行モード(^ $ が各行に対応)
/hello/i.test('HELLO');  // true(大文字小文字を無視)
'Hello hello'.match(/hello/gi);  // ['Hello', 'hello']

よく使うパターン

数字

/\d/      // 数字1文字(0〜9)
/\d+/     // 数字1文字以上
/\d{4}/   // 数字ちょうど4文字
/\d{2,4}/ // 数字2〜4文字

文字種

/\w/  // 英数字またはアンダースコア([a-zA-Z0-9_])
/\s/  // スペース・タブ・改行などの空白
/./   // 改行以外の任意の1文字

位置

/^hello/   // 行頭が「hello」
/hello$/   // 行末が「hello」
/^hello$/  // 「hello」だけ(完全一致)

よく使う実例

メールアドレスの簡易チェック

const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
emailRegex.test('user@example.com');  // true
emailRegex.test('invalid');           // false

電話番号(ハイフンあり・なし両対応)

const telRegex = /^0\d{1,4}-?\d{1,4}-?\d{4}$/;
telRegex.test('03-1234-5678');  // true
telRegex.test('0312345678');    // true

URLからドメイン部分を取得

const url = 'https://example.com/path?query=1';
const match = url.match(/https?:\/\/([^\/]+)/);
console.log(match[1]);  // 'example.com'

日付(YYYY-MM-DD形式)

const dateRegex = /^\d{4}-\d{2}-\d{2}$/;
dateRegex.test('2024-05-16');  // true
dateRegex.test('2024/05/16'); // false

キャプチャグループ

() で囲むと、マッチした部分を取り出せます。

const str = '2024-05-16';
const match = str.match(/(\d{4})-(\d{2})-(\d{2})/);
console.log(match[1]);  // '2024'(年)
console.log(match[2]);  // '05'(月)
console.log(match[3]);  // '16'(日)

replace() と組み合わせて日付フォーマットを変換することもできます。

'2024-05-16'.replace(/(\d{4})-(\d{2})-(\d{2})/, '$1年$2月$3日');
// '2024年05月16日'

TypeScriptで使う場合

TypeScriptでは match() の戻り値が RegExpMatchArray | null になるため、null チェックが必要です。

const str = 'today is 2024-05-16';
const match = str.match(/(\d{4}-\d{2}-\d{2})/);
if (match) {
  console.log(match[1]);  // '2024-05-16'
}

まとめ

やりたいこと 使うメソッド
含むか確認 regex.test(str)
マッチ部分を取得 str.match(regex)
置換 str.replace(regex, replacement)
分割 str.split(regex)
  • /パターン/フラグ で書くのが基本
  • g で全件、i で大文字小文字を無視
  • () でキャプチャグループを作るとマッチ部分を取り出せる

特定の文字に囲まれた中身を抜き出すパターンは「正規表現でカッコなどに囲まれた中身を抜き出す」で解説しています。

Rubyのバージョン管理:rbenv・miseの使い方と切り替え方法

Rubyのバージョン管理:rbenv・miseの使い方と切り替え方法

はじめに

Rubyを使っていると、こんな場面が出てきます。

  • プロジェクトAはRuby 3.1、プロジェクトBはRuby 3.3を使っている
  • チームの誰かの環境だけ動かない
  • 新しいRubyを試したいが、今の環境を壊したくない

バージョン管理ツールを使えば、プロジェクトごとにRubyのバージョンを自動で切り替えられます。この記事ではよく使われる rbenv と、最近人気の mise の使い方を解説します。


rbenvとmiseの違い

rbenv mise
特徴 Ruby専用のバージョン管理ツール Ruby以外の言語も管理できる
歴史 長く、情報が豊富 比較的新しい(旧rtx)
対応言語 Ruby Ruby、Node.js、Python、Goなど
設定ファイル .ruby-version .mise.toml または .ruby-version

単一言語なら rbenv、複数言語を一元管理したいなら mise がおすすめです。


rbenvを使う

インストール

Mac(Homebrew)

brew install rbenv ruby-build

シェルの設定ファイルに以下を追加します。

# ~/.zshrc
eval "$(rbenv init - zsh)"

設定を反映します。

source ~/.zshrc

インストール確認

rbenv --version
rbenv 1.3.0

Rubyをインストールする

インストール可能なバージョンを確認します。

rbenv install --list

特定のバージョンをインストールします。

rbenv install 3.3.0

バージョンを切り替える

グローバル(デフォルト)のバージョンを設定する

rbenv global 3.3.0

プロジェクト単位でバージョンを設定する

プロジェクトのディレクトリで以下を実行します。

rbenv local 3.3.0

.ruby-version ファイルが作成され、そのディレクトリ以下では自動的に指定したバージョンが使われます。

cat .ruby-version
# 3.3.0

現在のバージョンを確認する

rbenv version
3.3.0 (set by /path/to/project/.ruby-version)

miseを使う

インストール

Mac(Homebrew)

brew install mise

シェルの設定ファイルに以下を追加します。

# ~/.zshrc
eval "$(mise activate zsh)"

設定を反映します。

source ~/.zshrc

インストール確認

mise --version

Rubyをインストールする

インストール可能なバージョンを確認します。

mise ls-remote ruby

特定のバージョンをインストールします。

mise install ruby@3.3.0

バージョンを切り替える

グローバルのバージョンを設定する

mise use --global ruby@3.3.0

プロジェクト単位でバージョンを設定する

プロジェクトのディレクトリで以下を実行します。

mise use ruby@3.3.0

.mise.toml ファイルが作成されます。

[tools]
ruby = "3.3.0"

miseは .ruby-version ファイルも読み込むため、rbenvで管理されていたプロジェクトでもそのまま使えます。

現在のバージョンを確認する

mise current ruby
ruby  3.3.0

プロジェクトに参加したときの流れ

rbenvまたはmiseを使っているプロジェクトをクローンした場合、.ruby-version または .mise.toml に記載されたバージョンが必要です。

# クローン後
git clone https://github.com/example/project
cd project

# .ruby-versionを確認
cat .ruby-version
# 3.2.2

# 該当バージョンをインストール(rbenvの場合)
rbenv install 3.2.2

# または mise の場合
mise install

mise install は設定ファイルを読んで必要なバージョンを自動でインストールしてくれます。


まとめ

操作 rbenv mise
インストール brew install rbenv ruby-build brew install mise
Rubyインストール rbenv install 3.3.0 mise install ruby@3.3.0
グローバル設定 rbenv global 3.3.0 mise use --global ruby@3.3.0
プロジェクト設定 rbenv local 3.3.0 mise use ruby@3.3.0
現在のバージョン確認 rbenv version mise current ruby
  • rbenvはRuby専用で情報が豊富。Rubyしか使わないなら十分
  • miseはNode.js・Python・Goなど複数言語をまとめて管理できる
  • どちらも .ruby-version ファイルに対応しているので既存プロジェクトとの互換性あり
  • バージョン確認の方法は「RubyとRailsのバージョン確認方法」を参照

RubyとRailsのバージョン確認方法:gem・bundlerもまとめて解説

RubyとRailsのバージョン確認方法:gem・bundlerもまとめて解説

はじめに

Rubyプロジェクトを始めるとき、既存のプロジェクトに参加するとき、エラーが起きたとき、まず確認するのがRubyとRailsのバージョンです。

この記事では rubyrailsgembundler のバージョン確認コマンドをまとめて解説します。


Rubyのバージョンを確認する

ruby -v
# または
ruby --version
ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [arm64-darwin23]

Railsのバージョンを確認する

グローバルにインストールされたRailsを確認する

rails -v
# または
rails --version
Rails 7.1.3

プロジェクトで使われているRailsを確認する

bundle exec rails -v

bundle exec を使うとグローバルではなく、そのプロジェクトの Gemfile.lock に記載されたバージョンで実行します。プロジェクト内では bundle exec rails を使うのが基本です。


gemのバージョンを確認する

gem はRubyのパッケージ管理コマンドです。

gem -v
# または
gem --version
3.5.3

特定のgemがインストールされているか確認する

gem list rails
rails (7.1.3, 7.0.8)

複数バージョンがインストールされている場合はすべて表示されます。


bundlerのバージョンを確認する

bundlerはプロジェクトごとにgemのバージョンを管理するツールです。

bundle -v
# または
bundler -v
Bundler version 2.5.3

プロジェクトで使われているgemのバージョンを確認する

bundle list

Gemfile.lock に記載された全gemとバージョンが表示されます。特定のgemだけ確認したい場合は以下のようにgrepと組み合わせます。

bundle list | grep rails
  * rails (7.1.3)

グローバルとプロジェクトの優先順位

rails コマンドを実行したとき、グローバルとプロジェクトのどちらが使われるかは状況によって異なります。

実行方法 使われるrails
rails グローバル
bundle exec rails プロジェクトのGemfile.lockに従う

プロジェクト内では必ず bundle exec rails を使うことで、環境の違いによるバージョン不一致を防げます。


.ruby-versionでプロジェクトのRubyバージョンを確認する

プロジェクトのルートに .ruby-version ファイルがある場合、そこに使用するRubyバージョンが記載されています。

cat .ruby-version
3.3.0

rbenvやmiseなどのバージョン管理ツールを使っている場合、このファイルを元に自動でRubyバージョンが切り替わります。


バージョンが食い違うときのトラブルシューティング

rails -vbundle exec rails -v の結果が違う

グローバルとプロジェクトで別バージョンのRailsが入っています。プロジェクト内では bundle exec rails を使うことで解決します。

ruby: command not found が出る

Rubyがインストールされていないか、PATHが通っていません。rbenvやmiseでインストールした場合はシェルの設定ファイルにパスが追加されているか確認してください。

echo $PATH

bundle: command not found が出る

bundlerがインストールされていません。以下でインストールできます。

gem install bundler

まとめ

確認したいもの コマンド
Rubyのバージョン ruby -v
Railsのバージョン(グローバル) rails -v
Railsのバージョン(プロジェクト) bundle exec rails -v
gemのバージョン gem -v
bundlerのバージョン bundle -v
プロジェクトの特定gem bundle list | grep gem名
  • プロジェクト内では bundle exec rails を使うとバージョン不一致を防げる
  • .ruby-version ファイルでプロジェクトが要求するRubyバージョンを確認できる
  • Rubyのバージョン管理には rbenv・mise が便利(→別記事で解説)
  • バージョン管理の方法は「Rubyのバージョン管理:rbenv・miseの使い方と切り替え方法」を参照