みなさんRubyでの開発経験はありますか>?RubyのwebフレームワークであるRuby on Railsを使うと結構簡単に作成することも可能です.本記事ではRubyの基本的な文法からRailsを使ったWeb開発の手法まで広く紹介します.
他のチートシート
git/gh コマンド(gitコマンド以外にもgitの概念も書いてあります)
lazygit
Docker コマンド(dockerコマンド以外にもdockerの概念の記事へのリンクもあります)
ステータスコード
TypeScript
Go/Gorm
SQL
Vim
プルリクエスト・マークダウン記法チートシート
ファイル操作コマンドチートシート
VSCode Github Copilot拡張機能
OpenAI Assistants API
他のシリーズ記事
TypeScriptで学ぶプログラミングの世界
プログラミング言語を根本的に理解するシリーズです.
情報処理技術者試験合格への道[IP・SG・FE・AP]
情報処理技術者試験の単語集です.
IAM AWS User クラウドサービスをフル活用しよう!
AWSのサービスを例にしてバックエンドとインフラ開発の手法を説明するシリーズです.
Project Gopher: Unlocking Go’s Secrets
Go言語や標準ライブラリの深掘り調査レポートです.
Rubyの概要
Rubyはまつもとゆきひろ氏(Matz)によって1990年代に開発されたオブジェクト指向スクリプト言語である. 文法がシンプルで読みやすいことが大きな特徴で, 動的型付けを採用しているため, コードの記述量が少なく直感的に開発を進められる. また, Rubyの理念として「プログラマの幸せを考えたプログラミング言語」という方針が掲げられており, 使い心地のよい言語設計がなされている. Webアプリケーション開発はもちろん, コマンドラインでのスクリプトやインフラ管理, テスト自動化など, 幅広い分野で利用されている.
Rubyの主な特徴
1. すべてがオブジェクト
整数や文字列, trueやnilといった値まで含め, Rubyではあらゆるものがオブジェクトである. 統一的な書き方が可能であり, どの値にもメソッドを呼び出せる. 例えば整数に対してもメソッドを呼び出せる点は, 他の言語とは違うRubyの特徴である.
num = 10
puts num.class # => Integer
puts num.next # => 11
puts num.to_s # => "10"
str = "Hello"
puts str.class # => String
puts str.upcase # => "HELLO"
puts str.include?("H") # => true
2. 動的型付け
変数に型宣言を行わず, 代入されたオブジェクトの型が自動的に適用される. 同じ変数に数値を代入したり文字列を代入したりできる柔軟さがある一方で, 静的型チェックがないため, 実行前に型の不整合を検出しにくい. テストや型解析ツール(Sorbetなど)を組み合わせることで, 大規模開発でも十分に運用できる.
value = 100
puts value.class # => Integer
value = "hundred"
puts value.class # => String
3. オブジェクト指向設計のしやすさ
Rubyにはクラスやモジュール, 継承, ミックスインといった仕組みがあり, オブジェクト指向を自然に表現できる. また, メタプログラミングにより動的にメソッドを生成するなど高度な機能も備える.
class Animal
def speak
"..."
end
end
class Dog < Animal
def speak
"Woof!"
end
end
dog = Dog.new
puts dog.speak # => "Woof!"
# モジュールをミックスイン
module Greeting
def greet
"Hello from #{self.class}"
end
end
class Person
include Greeting
end
alice = Person.new
puts alice.greet # => "Hello from Person"
# メタプログラミング例: 動的にメソッドを作る
class DynamicExample
[:foo, :bar, :baz].each do |name|
define_method(name) do
"Method #{name} called."
end
end
end
demo = DynamicExample.new
puts demo.foo # => "Method foo called."
puts demo.bar # => "Method bar called."
puts demo.baz # => "Method baz called."
4. 豊富なライブラリとフレームワーク
標準ライブラリはもちろん, インターネット上には数多くのGemが公開されており, Web開発におけるRuby on RailsやSinatra, インフラ管理におけるChef, テストにおけるRSpecなど, 多岐にわたるフレームワークが存在する. これらを活用することで, 開発生産性を大幅に高めることができる.
Rails風のイメージ
# Railsの場合, コントローラ内で以下のようなコードを書き,
# Active Recordを使ってDBとやりとりすることが可能.
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
end
end
# RSpecを使ったテストの例
RSpec.describe "Sample test" do
it "tests if 2+3 equals 5" do
expect(2+3).to eq(5)
end
end
5. DSL(Domain Specific Language)の構築が容易
Rubyの文法はカッコの省略やブロック構文などが柔軟であり, 人間が読み書きしやすいDSLを作るのに向いている. RakeやChefなどはRubyで書かれたDSLの代表例であり, コードがまるで設定ファイルのように読みやすい.
# Rakefile (ビルドタスクのDSL)
task :hello do
puts "Hello from Rake task"
end
desc "Sample task with a parameter"
task :greet, [:name] do |_task, args|
name = args[:name] || "Ruby"
puts "Hello, #{name}!"
end
# コマンドラインで以下のように実行
# rake hello
# rake greet[Alice]
6. ガーベジコレクション(GC)の採用
RubyにはGC(Garbage Collection)があり, 不要になったオブジェクトを自動的にメモリから解放してくれる. これによりメモリ管理の煩雑さを軽減し, バグの原因となるメモリリークを起こしにくい. 開発者はビジネスロジックの実装に集中しやすくなる.
# メモリ管理のコードを書く必要がない
def create_lots_of_strings
100.times do |i|
s = "String number #{i}"
# このスコープを抜けると, sへの参照がなくなるためGCの対象となる
end
end
create_lots_of_strings
puts "Finished creating strings"
このように, Rubyはプログラマが心地よく開発できるよう設計されており, 幅広い分野で活躍することができる. 静的型付き言語にはない柔軟性と, 豊富なライブラリが相まって, さまざまなニーズに応えられる点が大きな魅力である.
Rubyを学ぶ意義
Rubyを学ぶことで, 直感的なコードの書き方を身につけながら, オブジェクト指向プログラミングへの理解を深めることができる. また, Webアプリケーション開発においてはRuby on Railsという強力なフレームワークがあるため, サービス開発の立ち上げがスピーディに行える. テストフレームワークや自動化ツールなどを駆使して, 開発効率と保守性を高める手法も合わせて習得できる. 「プログラマの幸せを願う言語設計」が体現されており, 一度使うと他の言語でも同様の快適さを追求したくなる, そんな魅力を持っている.
Rubyの歴史や用途
Rubyは1995年に初めて公開され, 当初は日本国内で徐々にユーザを増やしていた. 2004年にRuby on Railsが登場すると, 英語圏を中心に世界的な注目を集めるようになり, Web開発の分野で急速に普及した. その後, Rails以外のフレームワークやライブラリも充実していき, インフラ管理(Chef), テストツール(RSpec, Minitest), 構成管理など, 多方面で利用されている. 現在でもRuby 3以降のバージョンアップが続いており, 並列処理やパフォーマンス向上のための機能追加が活発に行われている.
Rubyを実行してみよう
Rubyでファイルを実行するときは,
ruby スクリプト名.rb
と入力する. コードをirb(Interactive Ruby)で試してみる場合は,
irb
を実行するだけで対話型シェルが起動し, 一行ずつ入力したコードを即座に評価して結果を得られる. 以下のように数値演算を試すことができる.
irb(main):001:0> 2 + 3
=> 5
irb(main):002:0> "Ruby".upcase
=> "RUBY"
このように, スクリプトファイルで書く前に動作確認を手軽に行うことが可能である.
RubyでHelloWorld
Rubyでは最もシンプルなプログラムとして, 画面に"Hello World"と出力するスクリプトを作ることができる. 次の例をhello.rbというファイルに記述したとする.
puts "Hello World"
Rubyでは出力方法として主にpとputsの2つがある
putsは人間が読みやすい形で出力を行い, 文字列の場合はクォートを省略して表示する. 一方pはデバッグ用途に適しており, 文字列はクォート付きで出力され, 配列は[1, 2, 3]のように構造を含めた形で表示される. また, putsがnilを返すのに対し, pは入力された値をそのまま返すため, メソッドチェーンで利用できるという特徴がある.
text = "Hello"
array = [1, 2, 3]
nil_value = nil
puts text # => Hello
puts array # => 1
# 2
# 3
puts nil_value # => (空行を出力)
p text # => "Hello"
p array # => [1, 2, 3]
p nil_value # => nil
ファイルを保存後, 端末で以下を実行する.
ruby hello.rb
すると, 画面に"Hello World"という文字列が表示される. この一行のコードからも分かる通り, Rubyはシンプルで分かりやすい文法を備えている.
ここまでで主な概要は示したが, 実際の開発では変数やデータ型, 制御構文, クラスの定義, メソッドの記述などを組み合わせ, より複雑なプログラムを構築していく. Ruby独自の柔軟な書き方を活かすことで, 開発者に優しいコードを多く書ける点が特徴である.
Rubyの基本文法
変数宣言
Rubyでは変数の型を明示的に指定する必要がなく, 代入した値に基づいて動的に型が決定される. 変数名には英数字とアンダースコアが使え, 小文字で始まるのが一般的である. 例えば, greeting, number, is_ruby_funという3つの変数を以下のように定義できる.
greeting = "こんにちは"
number = 42
is_ruby_fun = true
puts greeting
puts number
puts is_ruby_fun
上記の例では, greetingには文字列(String), numberには整数(Integer), is_ruby_funには真偽値(TrueClass)が代入されている. Rubyではこれらの変数を別の型の値に再代入することもできる.
number = 42
puts number.class # => Integer
number = "四十二"
puts number.class # => String
このように一度整数を代入した変数に, 後から文字列を代入しても問題なく実行できる. ただし, 動的型付けゆえに誤った型同士の演算を実行時に発見するケースがあるため, 大規模な開発ではテストをしっかり書いたり, 型解析ツールを導入したりすることが多い.
演算子(算術, 比較など)
Rubyでは算術演算子や比較演算子を用いて数値演算や条件式を記述できる.
算術演算子
+ (足し算),
- (引き算),
* (掛け算),
/ (割り算),
% (剰余),
** (累乗)
x = 10
y = 3
sum = x + y # 10 + 3 => 13
difference = x - y # 10 - 3 => 7
product = x * y # 10 * 3 => 30
quotient = x / y # 10 / 3 => 3 (整数同士の割り算の場合, 小数点以下は切り捨て)
remainder = x % y # 10 % 3 => 1
power = x ** y # 10 ** 3 => 1000
puts sum
puts difference
puts product
puts quotient
puts remainder
puts power
なお, x / yが3ではなく3.3333...を期待する場合は, 浮動小数点(Float)の値を使う.
x = 10.0 # float
y = 3
quotient = x / y # 10.0 / 3 => 3.3333333333333335
puts quotient
比較演算子
==, !=, >, <, >=, <=, <=>, ===などがある. 代表的なものを紹介する.
a = 5
b = 7
puts a == b # => false
puts a != b # => true
puts a < b # => true
puts a > b # => false
puts a <=> b # => -1 (aがbより小さいので-1)
宇宙船演算子<=>
a <=> bは通称「宇宙船演算子」と呼ばれ, 左辺が右辺より小さい(a < b)場合は-1, 等しい場合(a == b)は0, 大きい場合(a > b)は1を返す. ソートのアルゴリズムなどで利用されることがある.
# 基本的な数値の比較
puts 1 <=> 1 # => 0 (等しい)
puts 1 <=> 2 # => -1 (左が小さい)
puts 2 <=> 1 # => 1 (左が大きい)
# 配列のソートでの使用例
fruits = ['banana', 'apple', 'cherry']
sorted_fruits = fruits.sort { |a, b| a <=> b }
p sorted_fruits # => ["apple", "banana", "cherry"]
# 文字列の比較
puts "apple" <=> "banana" # => -1
puts "cherry" <=> "banana" # => 1
puts "apple" <=> "apple" # => 0
# 浮動小数点数の比較
puts 1.5 <=> 2.5 # => -1
puts 2.5 <=> 2.5 # => 0
puts 3.5 <=> 2.5 # => 1
# カスタムクラスでの使用例
class Person
include Comparable
attr_reader :name, :age
def initialize(name, age)
@name = name
@age = age
end
def <=>(other)
age <=> other.age
end
end
alice = Person.new("Alice", 20)
bob = Person.new("Bob", 25)
puts alice <=> bob # => -1
===演算子
===演算子はcase式での比較やRangeオブジェクトの一致判定などに使われる.
range = (1..10)
puts range === 5 # => true
puts range === 11 # => false
case "hello"
when String # String === "hello" が評価される
puts "文字列です"
end
従来の==演算子と===演算子を比較
===を使う場合
case age
when 0..12
"子供"
when 13..19
"十代"
end
従来の比較(==)演算子を使う場合
if age >= 0 && age <= 12
"子供"
elsif age >= 13 && age <= 19
"十代"
end
データ型(数値, 文字列, 配列, ハッシュなど)
Rubyではさまざまな種類のデータをオブジェクトとして扱う. よく使われる代表的なデータ型を以下に示す.
1. 数値(Integer, Float)
整数(Integer)と浮動小数点数(Float)があり, 数値リテラルとして代入する. 整数が非常に大きくなると, 自動的にBigInteger扱いとなり, オーバーフローが発生しないのが特徴である.
int_num = 123
float_num = 3.14
puts int_num.class # => Integer
puts float_num.class # => Float
big_num = 999999999999999999999999999999
puts big_num.class # => Integer (大きい値でもIntegerになる)
2. 文字列(String)
ダブルクォートとシングルクォートで表記方法が異なり, ダブルクォート内では式展開(#{...})や特殊文字のエスケープが有効になる. シングルクォートではそれらは行われない.
str_double = "Ruby\nLanguage"
str_single = 'Ruby\nLanguage'
puts str_double # => 改行を含む
puts str_single # => バックスラッシュ付きで出力される
name = "Alice"
puts "Hello, #{name}" # => "Hello, Alice"
3. 配列(Array)
Rubyの配列は順序付きの要素を格納するコレクションである. 要素には文字列, 数値, 真偽値, さらには他の配列やハッシュなど, あらゆるオブジェクトを入れることができる.
配列の作成と初期化
配列は角括弧[]で作成し, あらかじめ要素を指定する方法と空の配列を用意して後から要素を追加する方法がある.
colors = ["red", "green", "blue"]
puts colors.inspect # => ["red", "green", "blue"]
empty_arr = []
puts empty_arr.inspect # => []
mixed_arr = [1, "two", :three, [4, 5]]
puts mixed_arr.inspect # => [1, "two", :three, [4, 5]]
arr = []
puts arr.class # => Array
配列の出力におけるpとputsの違い
str = "Hello"
num = 123
arr = [1, 2, 3]
nil_val = nil
# puts:人が読みやすい形で出力
puts str # => Hello
puts num # => 123
puts arr # => 1
# 2
# 3
puts nil_val # => (空行を出力)
# p:デバッグ向き。オブジェクトの詳細情報を出力
p str # => "Hello" (文字列はクォートつきで出力)
p num # => 123
p arr # => [1, 2, 3] (配列は1行で構造も含めて出力)
p nil_val # => nil (nilもちゃんと表示)
要素のアクセス
インデックス(添字)を指定して要素を取得する. 先頭要素は0番目, 負のインデックスで後ろから数えられる.
colors = ["red", "green", "blue", "yellow"]
puts colors[0] # => "red"
puts colors[2] # => "blue"
puts colors[-1] # => "yellow"
puts colors[1..2].inspect # => ["green", "blue"]
要素の追加と削除(push, pop, shift, unshift)
pushと<<は配列の末尾に要素を追加し, popは末尾から要素を取り出す. shiftとunshiftで先頭要素を取り出したり追加したりできる.
numbers = [1, 2, 3]
numbers.push(4) # => [1, 2, 3, 4]
numbers << 5 # => [1, 2, 3, 4, 5]
popped = numbers.pop # => 5
puts popped # => 5
puts numbers.inspect # => [1, 2, 3, 4]
numbers.shift # => 1
numbers.unshift(0) # => [0, 2, 3, 4]
puts numbers.inspect # => [0, 2, 3, 4]
任意の位置への挿入と削除
insertメソッドを使って特定のインデックスへ要素を追加し, delete_atで特定インデックスの要素を削除できる.
arr = [10, 20, 40]
arr.insert(2, 30) # => [10, 20, 30, 40]
arr.delete_at(0) # => 10(削除された値)
puts arr.inspect # => [20, 30, 40]
要素の一部を取得や切り出し(slice, values_at)
範囲指定やslice, values_atなどで配列の一部を取り出せる.
arr = ["a", "b", "c", "d", "e"]
puts arr.slice(1, 3).inspect # => ["b", "c", "d"]
puts arr[1..3].inspect # => ["b", "c", "d"]
puts arr.values_at(0, 2, 4).inspect # => ["a", "c", "e"]
配列の連結や結合(concat, +)
配列同士を結合するにはconcat(破壊的)や+演算子(非破壊的)を使う.
arr1 = [1, 2]
arr2 = [3, 4]
arr1.concat(arr2)
puts arr1.inspect # => [1, 2, 3, 4]
arr3 = [1, 2]
arr4 = [3, 4]
arr5 = arr3 + arr4
puts arr3.inspect # => [1, 2]
puts arr5.inspect # => [1, 2, 3, 4]
繰り返し処理(each, each_with_indexなど)
配列の要素を順番に処理したい場合はeachやeach_with_indexを使う.
colors = ["red", "green", "blue"]
colors.each do |color|
puts "Color: #{color}"
end
colors.each_with_index do |color, index|
puts "#{index}: #{color}"
end
要素の変換(map, collect)
mapやcollectメソッドで各要素を変換した結果を新しい配列として返す.
nums = [1, 2, 3, 4]
squared = nums.map { |n| n * n } # => [1, 4, 9, 16]
puts squared.inspect
要素の絞り込み(select, reject, find)
selectはブロックがtrueを返す要素だけ残し, rejectはfalseを返す要素だけ残す. findは最初にマッチした要素を返す.
nums = [10, 15, 20, 25, 30]
bigger_than_20 = nums.select { |n| n > 20 }
puts bigger_than_20.inspect # => [25, 30]
not_divisible_20 = nums.reject { |n| n % 20 == 0 }
puts not_divisible_20.inspect # => [15, 25]
found = nums.find { |n| n >= 25 }
puts found # => 25
要素の探索(index, rindex, include?)
indexやrindexで検索を行い, include?で配列に要素が含まれるかどうかを判定する.
arr = ["apple", "banana", "cherry", "banana"]
puts arr.index("banana") # => 1
puts arr.rindex("banana") # => 3
puts arr.include?("cherry") # => true
配列の長さや要素数(length, size, count)
length, size, countは要素数を返し, countに引数を渡すとその値がいくつ含まれるかを数える.
arr = [1, 2, 2, 3]
puts arr.length # => 4
puts arr.count # => 4
puts arr.count(2) # => 2
並べ替え(sort, sort!)
sortは並び替えた新しい配列を返し, sort!は配列を破壊的に並び替える.
arr = [3, 1, 5, 2, 4]
sorted_arr = arr.sort
puts sorted_arr.inspect # => [1, 2, 3, 4, 5]
puts arr.inspect # => [3, 1, 5, 2, 4]
arr.sort!
puts arr.inspect # => [1, 2, 3, 4, 5]
重複やnil要素を除去(uniq, compact)
uniq, compactはそれぞれ重複要素やnil要素を取り除く. 破壊的メソッドとしてuniq!, compact!も存在する.
arr = [1, 2, 2, 3, nil, 3]
puts arr.uniq.inspect # => [1, 2, 3, nil]
puts arr.inspect # => [1, 2, 2, 3, nil, 3]
arr.uniq!
puts arr.inspect # => [1, 2, 3, nil]
arr.compact!
puts arr.inspect # => [1, 2, 3]
文字列との変換(join, flatten)
joinは配列の要素を連結して文字列を作る. flattenで多次元配列を1次元化する.
arr = ["Ruby", "is", "fun"]
puts arr.join(" ") # => "Ruby is fun"
multi_arr = [[1, 2], [3, 4, [5]]]
puts multi_arr.flatten.inspect # => [1, 2, 3, 4, 5]
その他の便利メソッド(sum, sample, shuffle, combination, permutation, transpose, product)
sumで要素を合計でき, sampleでランダム要素を取得, shuffleで配列をランダムに並び替えられる. また, combinationやpermutationで組み合わせや順列を生成でき, transposeやproductなど行列計算やデカルト積にも対応する.
nums = [1, 2, 3, 4]
puts nums.sum # => 10
puts nums.sample # => ランダムで1,2,3,4のいずれか
puts nums.shuffle.inspect # => 要素がランダムに並び替えられた新配列
comb = nums.combination(2).to_a
puts comb.inspect # => [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
perm = nums.permutation(2).to_a
puts perm.inspect # => [[1, 2], [1, 3], ...
p1 = [1, 2]
p2 = ["A", "B"]
puts p1.product(p2).inspect # => [[1, "A"], [1, "B"], [2, "A"], [2, "B"]]
Rubyの配列は非常に豊富なメソッドを備えており, 各種の追加・削除, 検索, 加工が簡単に行える. 特にイテレータメソッドや変換メソッドを活用すると, 短いコードで複雑な処理を表現できる.
多次元配列
多次元配列とは配列の中に配列が入れ子になった構造で,行列やテーブルのようなデータを表現するのに適している.要素へのアクセスはarray[n][m]のように複数の角括弧を使い,最初の添字で外側の配列の位置を,次の添字で内側の配列の位置を指定する.
# 2次元配列の作成と操作
matrix = [
[1, 2, 3], # インデックス[0]の配列
[4, 5, 6], # インデックス[1]の配列
[7, 8, 9] # インデックス[2]の配列
]
# 要素へのアクセス
puts matrix[1][2] # => 6 (2行目の3番目の要素)
puts matrix[0][0] # => 1 (1行目の1番目の要素)
puts matrix[2][2] # => 9 (3行目の3番目の要素)
# 配列の変更
matrix[1][1] = 10 # 真ん中の要素を変更
p matrix # => [[1, 2, 3], [4, 10, 6], [7, 8, 9]]
# 行の追加
matrix.push([10, 11, 12])
p matrix # => [[1, 2, 3], [4, 10, 6], [7, 8, 9], [10, 11, 12]]
# 様々な作成方法
# Array.newを使用した初期化
matrix2 = Array.new(3) { Array.new(3, 0) }
p matrix2 # => [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
# 各要素に対する操作
matrix.each do |row|
row.each do |element|
print "#{element} "
end
puts # 改行
end
# 配列の変換
# 各要素を2倍にする
doubled = matrix.map do |row|
row.map { |element| element * 2 }
end
p doubled
# 3次元配列の例
cube = [
[[1, 2], [3, 4]],
[[5, 6], [7, 8]]
]
puts cube[1][0][1] # => 6 (2層目の1行目の2番目の要素)
# 特定の値で初期化された大きな配列
# 5x5のチェス盤のような配列を作成
board = Array.new(5) { Array.new(5, "*") }
p board
4. ハッシュ(Hash)
キーと値をセットで扱うデータ構造で, Pythonの辞書型やJavaScriptのオブジェクトに相当する. キーをシンボル(:nameのような形式)や文字列, 数値など様々なオブジェクトにできる.
person = { name: "Alice", age: 20 }
puts person[:name] # => "Alice"
person[:job] = "Engineer" # 新しいキーを追加
puts person.inspect # => {:name=>"Alice", :age=>20, :job=>"Engineer"}
文字列キーのハッシュ
scores = { "math" => 90, "english" => 85 }
puts scores["math"] # => 90
eachメソッドでキーと値を取得
scores.each do |subject, point|
puts "#{subject}: #{point}"
end
ハッシュのメソッド
puts person.keys.inspect # => [:name, :age, :job]
puts person.values.inspect # => ["Alice", 20, "Engineer"]
キーの順序はRuby 1.9以降維持されるようになっており, 入れた順番通りに取り出すことができる.
以上のように, Rubyでは一つの変数に文字列や数値, 配列やハッシュといった様々な型を代入し, それらを組み合わせることで柔軟なプログラムを構築する. 動的型付けならではの書きやすさと, 豊富なメソッドが提供される標準ライブラリのおかげで, 少ないコード量で多様な処理を実装できる点が大きな利点である.
条件分岐(if...else文, case文, ?演算子, ネスト)
Rubyにはさまざまな条件分岐が用意されており, プログラムの流れを制御しやすい. 代表的な構文を順に見ていく.
if...else文
条件式がtrueならばif節の処理が, falseならばelse節の処理が実行される. さらに複数の条件を判定したい場合はelsifを挟んで連鎖的にチェックできる.
score = 85
if score >= 90
puts "Excellent"
elsif score >= 70
puts "Good"
else
puts "Needs Improvement"
end
上記ではscoreが90以上なら"Excellent"を, 70以上なら"Good"を, それ以外なら"Needs Improvement"を表示する. また, elsifは何度でも続けられるが, 条件分が多いときは可読性に注意が必要である.
ネストしたif文
if文の中にさらにif文を入れることもできる. しかし, 深すぎるネストは可読性を下げる原因となるため, 条件分岐が複雑になる場合は別の手段(早期returnやcase文の活用など)を検討する.
score = 78
if score >= 70
if score >= 90
puts "Excellent"
else
puts "Good"
end
else
puts "Needs Improvement"
end
この例ではまずscoreが70以上かを判定し, 70以上なら今度は90以上かどうかを判定している.
unless文
ifの逆の条件である, "もし~でなければ" という意味を持つunless文もある. if文で否定条件を書くよりも可読性が高くなる場合がある.
is_logged_in = false
unless is_logged_in
puts "ログインしてください"
end
上記の例はif !is_logged_inと書くのと同等である.
case文
複数の条件分岐を分かりやすく書ける構文としてcase文がある. 判定したいオブジェクトや値をcaseのあとに置き, when節で各条件を記述する.
signal = "yellow"
case signal
when "red"
puts "Stop"
when "green"
puts "Go"
when "yellow"
puts "Caution"
else
puts "Unknown signal"
end
signalの値に応じて出力を切り替えている. else節に相当するものはcase文ではwhen以外のパターンにマッチしなかった場合の処理を定義できる.
case文の拡張例
Rubyでは===演算子を活用して, より複雑な判定をcase文で行うこともできる. 例えば数値がある範囲に含まれているかどうかを調べるといった使い方が可能である.
score = 68
case score
when 0..59
puts "Failed"
when 60..79
puts "Passed"
when 80..89
puts "Good"
when 90..100
puts "Excellent"
else
puts "Out of range"
end
ここではスコア(score)の値が0から59の範囲であれば"Failed", 60から79なら"Passed"というように, 範囲指定をシンプルに書ける.
?演算子(三項演算子)
if...else文を簡潔に書きたい場合は?演算子を使う. "条件式 ? 真の場合 : 偽の場合"という形で1行にまとめられる.
age = 18
puts age >= 20 ? "Adult" : "Minor"
上記の例ではage >= 20がtrueなら"Adult", falseなら"Minor"を出力する. ただし, この三項演算子を多用しすぎるとコードが読みにくくなる場合があるので, 適度に活用することが望ましい.
if修飾子とunless修飾子
1行でシンプルな判定と処理を行うための構文としてif修飾子やunless修飾子がある. 後置if/後置unlessとも呼ばれ, 以下のように書ける.
score = 100
puts "Perfect!" if score == 100
is_debug_mode = false
puts "Debug mode is ON" unless is_debug_mode
if修飾子の場合は"if 条件"を行末に置き, unless修飾子の場合は"unless 条件"を行末に置く. 複雑な処理には向かないが, 単純な判定と1行出力が同時に必要なときは可読性が向上する.
繰り返し処理(while文, until文, for文, eachイテレータなど)
Rubyには複数の繰り返し方法があり, コードの意図に合わせて使い分けられる. さらにbreak, next, redoなどの制御構文を組み合わせることで, 柔軟なループ処理を記述できる.
while
条件が真の間ループを継続する. 条件が最初にチェックされるので, 必要に応じて条件変数を更新しないと無限ループが発生する可能性がある.
count = 0
while count < 5
puts count
count += 1
end
上記ではcountが5未満の間, ループが繰り返される. 毎回countをインクリメントしていき, countが5になった時点でループを抜ける.
until
条件が偽の間ループを継続する構文である. 直感的にはwhile文の逆バージョンであり, do...while構文のように使われることが多い.
count = 5
until count == 0
puts count
count -= 1
end
countが0になるまで, つまりcount == 0がtrueになるまでループを実行し続ける. したがって5,4,3,2,1と出力され, countが0になるとループを抜ける.
for
C言語などに近い構文だが, Rubyでは内部的にeachを呼び出している. 通常は配列や範囲オブジェクト(1..3など)を指定し, 要素を順に取り出す.
for i in 1..3
puts i
end
rrr
1,2,3と順に出力される. Rubyの慣習としてはfor文よりeachイテレータを多用する場合が多い.
### eachイテレータ
ブロックを用いて配列などの要素を順に処理する. breakやnextなどを組み合わせると, ループを細かく制御できる.
```rb
[1,2,3,4,5].each do |n|
break if n > 3
next if n == 2
puts n
end
この例ではnが2のときはnextでスキップし, nが4を超えたときはbreakでループを終了する. 結果的に1と3のみが出力される.
loop do文
Ruby独自のloop do ... end構文を使えば, 条件判定を任意のタイミングで行いつつ永遠に繰り返すループを記述できる.
count = 0
loop do
count += 1
puts "Looping... #{count}"
break if count >= 3
end
ここではbreakが呼ばれるまで繰り返しが続き, countが3になった時点でループが抜けられる.
制御構文: break, next, redoなど
Rubyの繰り返し処理には, breakやnext, redoなどの制御構文が用意されている. それぞれの挙動を理解して使い分けることで, より柔軟なループ処理を実現できる. また, Ruby 2.0まではretryも存在したが, 現在は非推奨である.
break
ループ全体を抜ける. 例えば, iが5になったらループを終了したい場合に使う.
10.times do |i|
if i == 5
break
end
puts i
end
# => 0,1,2,3,4 で終了
next
現在の繰り返しだけをスキップし, 次の繰り返しへ移る. 例えば, iが2のときだけ出力を飛ばす.
10.times do |i|
if i == 2
next
end
puts i
end
# => 0,1,(2はスキップ),3,4,5,6,7,8,9
redo
今の繰り返しを最初からやり直す. ただし条件式は再評価されないため, 使い方を誤ると無限ループに陥りやすい.
count = 0
5.times do |i|
if i == 2 && count < 2
count += 1
puts "Redo at i=#{i}, count=#{count}"
redo # iの値を変えないままループをやり直す
end
puts i
end
# この例では, i=2に初めて到達したときredoを実行し,
# 再びi=2の処理が行われる(countが増加).
# countが2になるまでredoが繰り返される.
# 出力イメージ:
# 0
# 1
# Redo at i=2, count=1
# Redo at i=2, count=2
# 2
# 3
# 4
この例では, 0,1の後に2でスキップして, 3,4と出力, 5でbreakして終了する. したがって結果的に0,1,3,4が出力される.
メソッド
1. メソッドの基本定義
Rubyにおいてメソッドはdef
キーワードで定義し, end
で終了する. クラスやモジュールの外側に定義したメソッドは「トップレベルメソッド」と呼ばれ, そのまま呼び出すことができる. (実際にはObjectクラスの特異メソッドとして定義される)
def say_hello
puts "Hello, world!"
end
say_hello # => "Hello, world!"
- メソッド名は小文字またはアンダースコアで始めるのが一般的.
-
def say_hello; ... ; end
のように1行で定義することも可能.
2. 引数の渡し方
(1) 通常の引数
複数の引数はカンマで区切る. 必要に応じてデフォルト値を設定したり, キーワード引数を使ったりできる.
def greet(name, language)
puts "Hello, #{name}. Programming language is #{language}."
end
greet("Alice", "Ruby")
# => "Hello, Alice. Programming language is Ruby."
(2) デフォルト引数
引数にデフォルト値を与えると, 呼び出し時に対応する引数を省略可能になる.
def greet(name = "Guest", language = "Ruby")
puts "Hello, #{name}. Language is #{language}."
end
greet
# => "Hello, Guest. Language is Ruby."
greet("Bob")
# => "Hello, Bob. Language is Ruby."
greet("Carol", "Python")
# => "Hello, Carol. Language is Python."
(3) キーワード引数
Ruby 2.0以降で導入された機能で, 引数を「キー: 値」の形式で受け取る. 順番に依存せずに渡せる利点がある. デフォルト値の指定も可能.
def user_info(name:, age:, country: "Japan")
puts "Name: #{name}, Age: #{age}, Country: #{country}"
end
user_info(name: "Dave", age: 32)
# => "Name: Dave, Age: 32, Country: Japan"
user_info(age: 25, name: "Erica", country: "USA")
# => "Name: Erica, Age: 25, Country: USA"
(4) 可変長引数(スプラット引数)
引数の数が不定の場合に, *args
として受け取ることができる. また, キーワード引数を不定個受け取る**opts
もある.
def sum_numbers(*nums)
nums.sum
end
puts sum_numbers(1,2,3,4,5) # => 15
puts sum_numbers(10, 20) # => 30
def show_options(**opts)
puts opts.inspect
end
show_options(color: "red", size: 10)
# => {:color=>"red", :size=>10}
3. 戻り値について
Rubyでは、メソッドの最後に評価された式がそのメソッドの戻り値となる. return
を省略することが多いが, 必要に応じて任意の箇所でreturn
を使って明示的に値を返すこともできる.
def add(a, b)
a + b # これが最後に評価されるので戻り値となる
end
puts add(2,3) # => 5
def subtract(a, b)
return a - b
end
puts subtract(5,2) # => 3
4. メソッド呼び出し時のカッコの省略
Rubyでは, 引数が一つの場合や, 文脈が明らかな場合はメソッド呼び出しの丸括弧()を省略できる. ただし, メソッドチェーンの可読性や引数の明示性を考慮して, チームごとのコーディング規約に合わせることが多い.
def greet(name)
"Hello, #{name}"
end
puts greet "Alice" # => "Hello, Alice"
# 書き方によっては曖昧になる場合があるので注意.
5. ブロック・yield・高階メソッドとの関係
Rubyでは「関数(メソッド)」に対してブロックを渡すことができる. このブロックはメソッド内でyield
を呼び出すことで実行される. Rubyのイテレータ(each, mapなど)はこれを活用している.
def with_logging
puts "Start"
yield if block_given? # ブロックが渡されていれば実行
puts "End"
end
with_logging do
puts "Processing..."
end
# =>
# Start
# Processing...
# End
-
block_given?
はメソッドにブロックが渡されているかを判定するメソッド. - ブロックを引数として受け取りたい場合は, 引数リストの最後に
&block
を指定する. するとブロックはProc
オブジェクトとして扱える.
def with_block(&block)
puts "Before block"
block.call
puts "After block"
end
with_block do
puts "Inside block"
end
# =>
# Before block
# Inside block
# After block
6. Proc・Lambda・メソッドオブジェクト
(1) Proc
Rubyではブロックをオブジェクト化したProc
クラスがあり, 関数ポインタのように扱える. Proc.new
で生成, あるいはproc { ... }
の糖衣構文で作成できる.
double_proc = Proc.new { |x| x * 2 }
puts double_proc.call(10) # => 20
(2) lambda
->(引数){ 処理 }
やlambda
キーワードで作成する. Procとの違いは, 引数のチェックの厳しさ, returnの振る舞い, selfの扱いなどが挙げられる. 一般にlambdaのほうが「メソッドライクな挙動」をする.
triple_lambda = ->(x){ x * 3 }
puts triple_lambda.call(5) # => 15
(3) メソッドオブジェクト
既存のメソッドをオブジェクトとして扱うには, method(:メソッド名)
を用いる. コールするときは.call
を使う.
def hello(name)
"Hello, #{name}"
end
hello_method = method(:hello)
puts hello_method.call("Ruby") # => "Hello, Ruby"
7. 特殊なメソッド(クラスメソッド・特異メソッド)
(1) クラスメソッド
クラス内部でdef self.method_name
と定義すると, クラスに紐づくメソッドとして呼び出せる.
後ほどオブジェクト指向プログラミングのセクションで説明する.
class MathUtil
def self.add(a, b)
a + b
end
end
puts MathUtil.add(2,3) # => 5
(2) 特異メソッド(オブジェクトのみに定義されたメソッド)
特定のインスタンスにだけメソッドを追加したい場合, class << obj
やdef obj.method_name
で定義できる. メタプログラミングでよく使われる手法.
str = "Hello"
def str.shout
upcase + "!!!"
end
puts str.shout # => "HELLO!!!"
# 他の文字列にはこのメソッドはない
8. メソッドのエイリアスと再定義
Rubyではalias
キーワードを使うと, 同じ実体を持つメソッドに別名を与えられる. 既存クラスや自作クラスのメソッドを再定義(オープンクラス)できる点もRubyの特徴である. ただし, 他人が作ったライブラリのメソッドを安易に再定義するのは衝突や混乱の元となるため注意が必要.
class String
alias :old_size :size
def size
puts "Calling my custom size method!"
old_size
end
end
str = "Hello"
puts str.size
# => "Calling my custom size method!"
# => 5
オブジェクト指向プログラミング(OOP)
Rubyはすべてがオブジェクトであり, OOPを自然に扱うための機能が豊富に用意されている. OOPとは, データ(インスタンス変数)と振る舞い(メソッド)をひとまとまりのクラス(オブジェクトの設計図)にまとめる設計思想である. これにより, コードの再利用性が高まり, メンテナンスしやすいプログラムを書くことができる.
オブジェクト指向についてはこの記事で(TypeScriptで書いてます...)
クラスの定義
クラスはclassキーワードで始め, endで終了する. Rubyにおけるコンストラクタはinitializeメソッドで実装し, インスタンス生成時に呼び出される. また, attr_accessor, attr_reader, attr_writerを使うことで, インスタンス変数のアクセサメソッドを自動で定義できる.
class Person
attr_accessor :name, :age
def initialize(name, age)
@name = name
@age = age
end
def greet
"Hello, I am #{@name}, and I am #{@age} years old."
end
end
alice = Person.new("Alice", 20)
puts alice.greet
alice.name = "Alicia"
puts alice.greet
上記ではattr_accessor :name, :ageを宣言しているため, alice.nameやalice.ageを直接参照したり, 再代入したりできる(getter, setterが自動生成される).
インスタンス変数とローカル変数
クラス内で@から始まる変数はインスタンス変数と呼ばれ, そのインスタンス専用のデータ領域として保持される. 一方, 単に小文字で始まる変数はローカル変数であり, メソッド内やブロック内でのみ有効である.
class Example
def initialize
@instance_var = "I'm an instance variable"
local_var = "I'm a local variable"
end
def show_variables
puts @instance_var
# puts local_var # これはエラーとなる(メソッドが異なるのでlocal_varが参照できない)
end
end
obj = Example.new
obj.show_variables
アクセス修飾子
Rubyではpublic, protected, privateの3種類のアクセス修飾子がある. デフォルトはpublicだが, コードの可読性を高めるために, メソッド定義の前にprivateなどを置いて以降のメソッドを非公開にする, というようにまとめて指定することが多い.
class Secret
def public_info
"This info is public."
end
private
def secret_info
"This info is hidden."
end
end
obj = Secret.new
puts obj.public_info # => "This info is public."
# puts obj.secret_info # => NoMethodError (private method呼び出しのため)
protectedは同じクラス, もしくはサブクラスのインスタンス同士からのみ呼び出せるときに使う. 実際にはpublicかprivateを使うことが多い.
継承とメソッドのオーバーライド
クラスの名前の後に<をつけ, その後に親クラスを指定することで継承関係を定義できる. サブクラスでは同名のメソッドを再定義(オーバーライド)することで, 親クラスの振る舞いを上書きできる. superキーワードを使って親クラスのメソッドを呼び出すこともできる.
class Animal
def speak
"..."
end
end
class Dog < Animal
def speak
"Woof!"
end
end
dog = Dog.new
puts dog.speak # => "Woof!"
# 親クラスのメソッドを呼びたい場合
class LoudDog < Dog
def speak
original = super # 親クラス(Dog)のspeakを呼び出す
"#{original} #{original}".upcase
end
end
loud_dog = LoudDog.new
puts loud_dog.speak # => "WOOF! WOOF!"
クラス変数とクラスメソッド
クラス全体で共有する変数を@@varのようなクラス変数として定義できる. また, クラスメソッドを定義するときはdef self.method_nameのように書くか, class << selfブロック内で定義する. ただし, クラス変数の使用は多人数開発では混乱を招きやすいとして推奨されない場合もあるため, 代わりにクラスインスタンス変数(@var)やシングルトンメソッドを使う場合が多い.
class Counter
@@count = 0
def initialize
@@count += 1
end
def self.total
@@count
end
end
obj1 = Counter.new
obj2 = Counter.new
puts Counter.total # => 2
抽象クラス
Rubyには言語仕様として抽象クラスという概念が存在しない. しかし, インスタンスを作ってほしくないクラスや, そのままでは動かない(サブクラスで実装してほしい)メソッドを含むクラスを作成したい場合は, コンストラクタでエラーを投げるなどの対応を行うことがある. また, moduleを使ってインターフェイス的に振る舞いを強制するデザインも可能である.
class AbstractAnimal
def initialize
if self.class == AbstractAnimal
raise "Cannot instantiate abstract class"
end
end
def speak
raise "Must implement speak in subclass"
end
end
class Cat < AbstractAnimal
def speak
"Meow!"
end
end
# 以下はエラーとなる
# abstract_animal = AbstractAnimal.new
cat = Cat.new
puts cat.speak # => "Meow!"
モジュール(Mixin)による多重継承の回避
Rubyは単一継承であり, 複数の親クラスを継承することはできない. 代わりにモジュールをincludeまたはextendすることで, クラスの機能を拡張するMixinが可能となっている.
module Loggable
def log(message)
puts "[LOG] #{message}"
end
end
class Machine
include Loggable
def start
log("Machine is starting...")
end
end
machine = Machine.new
machine.start # => [LOG] Machine is starting...
このように, Rubyのオブジェクト指向はシンプルな文法ながら強力で, 小規模から大規模開発まで幅広く対応できる. OOPの概念に慣れ親しんでいない場合でも, Rubyで学びやすい設計となっている.
Ruby on Railsチートシート
Ruby on Rails(以下Rails)はRuby言語で書かれたWebアプリケーションフレームワークである. 「プログラマの幸福」を重視するRubyの思想を色濃く受け継ぎ, “Convention over Configuration”(設定より規約)と “DRY”(Don’t Repeat Yourself) を理念として掲げている. Railsのコードを見れば分かるとおり, 開発者が最低限の設定を記述するだけで多くの作業が自動化され, 高い生産性を実現できる.
Railsの概念と歴史
Railsは2004年にDavid Heinemeier Hansson(DHH)によって開発が開始され, 2005年に正式にリリースされた. 当時, Ruby自体は日本国内ではある程度知られていたが, 国際的には今ほど普及していなかった. Railsの登場により, Rubyとセットで爆発的に広まり, Webアプリケーションフレームワークの代表格となった. Railsは“Convention over Configuration”を強く打ち出し, コードの記述量を大幅に削減できる点が注目を集めた. また, Active Recordパターンによる強力なORマッパーが標準搭載され, MVC(Model-View-Controller)アーキテクチャをベースにすることで, 分かりやすい構造のWebアプリケーションを作成しやすくなっている.
採用されているアーキテクチャ(MVC)
RailsはMVC(Model-View-Controller)をアプリケーション構造の中心に据えている.
1. Model
アプリケーションのビジネスロジックやデータベースとのやり取りを担う. RailsではActive Recordライブラリを通してテーブルとモデルが1対1で対応し, クエリをほぼ意識せずにデータ操作できる.
2. View
ユーザーが直接目にする部分で, HTMLやCSS, JavaScriptで構成される. RailsではERBやHaml, Slimなどのテンプレートエンジンが利用できる.
3. Controller
ModelとViewを仲介する役割を持つ. ルーティングから受け取ったリクエストを処理し, 必要なデータをModelに問い合わせ, レスポンスとしてViewに描画させる.
これらの役割が明確に分離されているため, コードの見通しが良く, 変更にも強いアプリケーションを開発できる.
MVCアーキテクチャの利点と他のアーキテクチャとの比較
1.MVCの主な利点
- モデル・ビュー・コントローラーの役割が明確に分かれており, コードの見通しが良い.
- ビジネスロジック(Model)とプレゼンテーション(View)が分離されているため, UIの変更が容易である.
- テストが書きやすく, ユニットテストの実施が容易である.
- 大規模なアプリケーション開発に適している.
2. 他のアーキテクチャとの比較
MVP (Model-View-Presenter)
- ViewとModelの依存関係が完全に分離されている.
- PresenterがViewとModelの橋渡しをする.
- MVCよりもView層のテストが容易である.
- コード量が多くなりがちである.
MVVM (Model-View-ViewModel)
- データバインディングを活用する.
- ViewとViewModelの関係が密接である.
- 主にクライアントサイドのアプリケーションで使用される.
- UIの状態管理が容易である.
Clean Architecture
- よりレイヤー化が進んだアーキテクチャである.
- 依存関係が内側に向かうように制御される.
- MVCよりも複雑だが, より厳密な責務の分離が可能である.
- 大規模システムに向いている.
どんなプロジェクトが向いているか
Railsは以下のようなプロジェクトで特に力を発揮する.
1. スタートアップやプロトタイプ作成
Scaffold(足場生成)などの機能により, とにかく素早く動くアプリを作りたいときに有利である.
2. 中規模から大規模のWebサービス
データベースを多用するサービスやECサイトなど, 多機能なWebアプリケーションを短期間で構築できる.
3. コミュニティやSNS, 予約システムなど
ユーザーアカウント管理や各種のRDB操作がセットになったWebアプリ全般に向いている.
一方で, 大量の同時接続が要求されるリアルタイム性が非常に高いサービス(ゲームサーバや超高トラフィックのチャットなど)には, イベント駆動や並行処理が得意な他の技術を組み合わせることが多い. もちろんRailsもマルチプロセスやスレッドを扱うが, GoやElixirなどの並行処理が得意な言語ほど特化はしていない.
GoやPythonとの違い
-
Go
静的型付け言語であり, 並列・並行処理が得意. 一方でWebフレームワークは多数あるがRailsほど「すぐに開発できる」統合的な仕組みが整備されているわけではない. 設定を明示的に行うことが多く, “Convention over Configuration”というRailsのような思想とは逆の方向性といえる. -
Python
動的型付けであり, DjangoやFlaskなどフレームワークは豊富. Webアプリだけでなく機械学習やデータサイエンスの分野でも強みを持つ. Railsに比べると「標準で全て揃う」というよりは, 組み合わせて自分に合ったスタックを作る印象が強い.
Railsは「とにかくWebアプリを素早く構築したい」「統合的なフレームワークを使いたい」場合に適しており, GoやPythonに比べるとプロトタイプを高速に開発できるメリットがある. しかし, 並行処理や軽量性の面ではGoの方が優れている, ML分野ではPythonが優れている, といった住み分けが存在する.
Railsの開発手法
Railsを使ったアプリケーション開発は, 「rails newコマンドでプロジェクトを作るところから始まり, モデルやコントローラを生成して機能を実装し, データベースをマイグレーションで管理しながら全体を仕上げる」という流れが基本となる. 主な手順を以下に挙げる.
1. Railsのインストールとプロジェクト作成
システムにRubyがインストールされていることを前提に, gemコマンドでRailsを導入する. その後, rails new コマンドで新規アプリケーションを生成する.
gem install rails
rails new myapp
cd myapp
2. MVCファイルの構成
生成したプロジェクトには, app/models, app/views, app/controllersというディレクトリが用意され, それぞれに対応するコードを置く. ルーティングはconfig/routes.rbで定義する.
Rails.application.routes.draw do
resources :users
end
3. モデルの作成とマイグレーション
rails generate model コマンドでモデルとマイグレーションファイル(データベースのスキーマを更新するためのファイル)を作成できる.
rails generate model User name:string email:string
rails db:migrate
これによりusersテーブルが作成され, Userモデルがapp/models/user.rbに生成される. Active Record経由でデータベース操作を行うため, SQLを書く必要が最小限で済む.
4. コントローラとアクションの定義
コントローラはrails generate controller コマンドで生成できる. ルーティング設定と組み合わせることで, URLやHTTPメソッドに応じてコントローラのアクションが呼び出される.
rails generate controller Users index show new create edit update destroy
これによりapp/controllers/users_controller.rbが生成され, その中でindex, show, newなどのアクションを定義できる. これらのアクションがViewと組み合わさって画面を描画したり, データベースを操作したりする.
5. Viewとテンプレートエンジン
Viewはapp/views以下にコントローラ名のディレクトリを作り, その中にアクション名と対応するHTMLテンプレート(erb, haml, slimなど)を配置する.
<!-- app/views/users/index.html.erb -->
<h1>User List</h1>
<ul>
<% @users.each do |user| %>
<li><%= user.name %> (<%= user.email %>)</li>
<% end %>
</ul>
6. Scaffoldによる自動生成
rails generate scaffold モデル名 ... コマンドを使うと, モデル, コントローラ, ビュー, ルート設定などが一度に生成される. プロトタイプ作成の段階で素早くCRUD機能を実装したい場合に便利である.
rails generate scaffold Post title:string content:text
rails db:migrate
これだけで投稿フォームや一覧, 詳細表示などが揃った簡易的なブログを作ることができる.
7. アセットパイプラインとフロントエンド
Railsにはアセットパイプラインという仕組みがあり, CSSやJavaScriptを効率的に管理, コンパイルできる. WebpackerやWebpackでモダンなフロントエンドツールとも連携し, ReactやVue.jsなどを組み込み可能.
8. テスト駆動開発(TDD)とRSpec
RailsではMinitestが標準で付属しているが, RSpecを使うプロジェクトも多い. Railsアプリの各レイヤ(Model, Controller, Featureなど)に対してテストを書き, バグを早期発見しやすくする.
RSpec.describe User, type: :model do
it "is invalid without a name" do
user = User.new(name: nil)
expect(user).not_to be_valid
end
end
9. デプロイと運用
Railsアプリを本番運用する場合, CapistranoやDocker, あるいはHerokuなどを使い, サーバへデプロイを行う. PumaやPassengerなどのアプリケーションサーバとNginxなどを組み合わせ, スケールに応じて設定を調整する.
Railsは, 「規約に従う」ことで開発者が必要最低限のことだけ記述すれば, Webアプリの基本的な機能やディレクトリ構造, ルーティングなどが自動的に整備される. これによりスタートアップや中規模から大規模のサービス開発まで対応可能であり, “開発の速さ”と“保守のしやすさ”のバランスが良い. 一方で, GoやPythonとは得意分野が異なり, 並列・並行処理や科学技術計算など別の分野では他の言語が適している場合もある. Railsを選択するメリットとしては, ユーザー認証やCRUD, テンプレートエンジンなどWebアプリに必要な機能がほぼ一式そろっているため, 立ち上げが非常に速い点が挙げられる. また, 大規模なエコシステムとコミュニティによってドキュメントや情報が豊富に存在しており, 開発者にとって学習やトラブルシューティングがしやすい.
Railsで簡単なUserモデルのAPIを作成する例
以下ではRailsのAPIモードを想定し, ユーザ情報(Userモデル)のCRUDを実装する最低限のソースコードを示す. Railsのバージョンは7.xを想定し, データベースはSQLite3を利用する. コマンドライン操作やファイル構成はローカル開発環境を前提とする.
① プロジェクトの作成
RailsのAPIモードを使う場合, --api オプションを付けてrails newコマンドを実行する.
rails new sample_api --api
cd sample_api
Gemfileなどは自動生成されるが, 今回はデフォルト構成のまま進める.
② データベース設定
デフォルトでSQLite3になっているため, そのまま利用する. config/database.ymlで接続設定が完了しているかを確認する(デフォルトのままでもOK).
③ モデルとマイグレーションの作成
ユーザの基本情報(name, email)を保持するUserモデルを作成する.
rails generate model User name:string email:string
上記コマンドで以下のようなファイルが生成される.
(日時部分は環境で異なる)
class CreateUsers < ActiveRecord::Migration[7.0]
def change
create_table :users do |t|
t.string :name
t.string :email
t.timestamps
end
end
end
class User < ApplicationRecord
validates :name, presence: true
validates :email, presence: true
end
④ マイグレーションの実行
DBにテーブルを作成する.
rails db:migrate
⑤ ルーティングの設定
APIとしてユーザデータを操作するエンドポイントを用意する. config/routes.rbを編集し, resources :usersを追記する.
Rails.application.routes.draw do
resources :users
end
これにより, /users へのGET/POST, /users/:id へのGET/PUT/PATCH/DELETEなどのルートが自動的に定義される.
⑥ コントローラの作成
rails generate controllerコマンドを使ってユーザ用コントローラを作成する. ただし, APIモードの場合はHTMLビューが不要なので, --no-assets --no-helperなどのオプションをつけるとよい. ここではシンプルに書く.
rails generate controller Users
app/controllers/users_controller.rb が作成されるので編集する. APIとしてJSONを返すことが前提のため, 各アクション内でrender json: ...の形式を用いる.
class UsersController < ApplicationController
# Rails 7のAPIモードではCSRF保護がデフォルトで無効になっているが,
# 通常のRailsモードであれば skip_before_action :verify_authenticity_token
# のように書く場合もある.
# GET /users
def index
users = User.all
render json: users
end
# GET /users/:id
def show
user = User.find(params[:id])
render json: user
rescue ActiveRecord::RecordNotFound
render json: { error: "User not found" }, status: :not_found
end
# POST /users
def create
user = User.new(user_params)
if user.save
render json: user, status: :created
else
render json: { errors: user.errors.full_messages }, status: :unprocessable_entity
end
end
# PATCH/PUT /users/:id
def update
user = User.find(params[:id])
if user.update(user_params)
render json: user
else
render json: { errors: user.errors.full_messages }, status: :unprocessable_entity
end
rescue ActiveRecord::RecordNotFound
render json: { error: "User not found" }, status: :not_found
end
# DELETE /users/:id
def destroy
user = User.find(params[:id])
user.destroy
render json: { message: "User deleted" }, status: :ok
rescue ActiveRecord::RecordNotFound
render json: { error: "User not found" }, status: :not_found
end
private
def user_params
params.require(:user).permit(:name, :email)
end
end
⑦ 動作確認
rails s
上記のコマンドでサーバを起動し, curlやHTTPクライアントを使って各エンドポイントにアクセスする. 以下に簡単な例を示す.
1) ユーザの一覧取得
GETリクエスト:
curl http://localhost:3000/users
2) ユーザの新規作成
POSTリクエスト:
curl -X POST -H "Content-Type: application/json" \
-d '{"user":{"name":"Alice","email":"alice@example.com"}}' \
http://localhost:3000/users
3) ユーザ詳細の取得
GETリクエスト:
curl http://localhost:3000/users/1
4) ユーザ情報の更新
PATCHリクエスト:
curl -X PATCH -H "Content-Type: application/json" \
-d '{"user":{"name":"Alicia"}}' \
http://localhost:3000/users/1
5) ユーザの削除
DELETEリクエスト:
curl -X DELETE http://localhost:3000/users/1
⑧ 全体ファイル構成(抜粋)
以下, rails new sample_api --api で作成した後に今回編集・追加した主なファイルを示す.
sample_api/
app/
controllers/
application_controller.rb # Rails APIモードで生成される
users_controller.rb # 追加
models/
user.rb # 追加
config/
routes.rb # 追記
db/
migrate/
20241225000000_create_users.rb # 生成されるマイグレーションファイル
Gemfile
Rakefile
...
これで簡単なUserモデルを用いたAPIサーバが完成する. 開発の要件に応じてバリデーションを追加したり, 認証・認可の仕組み(DeviseやJWTなど)を組み込んだり, テストフレームワーク(RSpecなど)で自動テストを書いたりしながら拡張していく.
railsのディレクトリ構造
Railsアプリケーションは多数のファイルとディレクトリが生成され, それぞれが明確な役割を担っている. 以下では, 質問中に示されているディレクトリ構造をベースに, 主なフォルダやファイルについて説明する.
❯ tree
.
├── Dockerfile
├── Gemfile
├── Gemfile.lock
├── README.md
├── Rakefile
├── app
│ ├── channels
│ │ └── application_cable
│ │ ├── channel.rb
│ │ └── connection.rb
│ ├── controllers
│ │ ├── application_controller.rb
│ │ ├── concerns
│ │ └── users_controller.rb
│ ├── jobs
│ │ └── application_job.rb
│ ├── mailers
│ │ └── application_mailer.rb
│ ├── models
│ │ ├── application_record.rb
│ │ ├── concerns
│ │ └── user.rb
│ └── views
│ └── layouts
│ ├── mailer.html.erb
│ └── mailer.text.erb
├── bin
│ ├── bundle
│ ├── docker-entrypoint
│ ├── rails
│ ├── rake
│ └── setup
├── config
│ ├── application.rb
│ ├── boot.rb
│ ├── cable.yml
│ ├── credentials.yml.enc
│ ├── database.yml
│ ├── environment.rb
│ ├── environments
│ │ ├── development.rb
│ │ ├── production.rb
│ │ └── test.rb
│ ├── initializers
│ │ ├── cors.rb
│ │ ├── filter_parameter_logging.rb
│ │ └── inflections.rb
│ ├── locales
│ │ └── en.yml
│ ├── master.key
│ ├── puma.rb
│ ├── routes.rb
│ └── storage.yml
├── config.ru
├── db
│ ├── migrate
│ │ └── 20241225032929_create_users.rb
│ ├── schema.rb
│ └── seeds.rb
├── lib
│ └── tasks
├── log
│ └── development.log
├── public
│ └── robots.txt
├── storage
│ ├── development.sqlite3
│ ├── development.sqlite3-shm
│ └── development.sqlite3-wal
├── test
│ ├── channels
│ │ └── application_cable
│ │ └── connection_test.rb
│ ├── controllers
│ │ └── users_controller_test.rb
│ ├── fixtures
│ │ ├── files
│ │ └── users.yml
│ ├── integration
│ ├── mailers
│ ├── models
│ │ └── user_test.rb
│ └── test_helper.rb
-
1. ルートディレクトリ直下
- Dockerfile: DockerコンテナでRailsアプリケーションを動かすための設定ファイル. 使用するRubyのバージョンやパッケージのインストール手順などを記述する.
- Gemfile / Gemfile.lock: Railsやその他のRubyライブラリ(gem)の依存関係を管理する. Gemfileに必要なgemを記述し, bundle installするとGemfile.lockが更新される.
- README.md: プロジェクトの説明やセットアップ方法, 使用方法などをドキュメントとしてまとめておくためのファイル.
- Rakefile: rakeコマンドで実行できるタスクを定義する. Railsだとデフォルトで多くのタスクが読み込まれる仕組みになっている.
- config.ru: Rack用の設定ファイル. RailsアプリケーションをRackサーバ(例: Puma, Passengerなど)で動かす際に利用される.
-
2. appディレクトリ
RailsのMVC構造の主要なコードが格納される. この下にモデルやコントローラ, ビューが配置される.-
app/channels: Action Cable(リアルタイム機能)のチャンネル関連ファイルを置く.
-
application_cable内には, channel.rbやconnection.rbがある.
- channel.rb: Action Cableで使用するチャンネルの共通機能.
- connection.rb: WebSocket接続における認証や接続時の処理を定義する.
-
application_cable内には, channel.rbやconnection.rbがある.
-
app/controllers: コントローラを置くディレクトリ.
- application_controller.rb: 全コントローラの親クラスとなるコントローラ. ここで共通処理やフィルタを定義することが多い. (Rails APIモードで生成される)
- users_controller.rb: ユーザ管理用のコントローラ.(先ほど追加したもの)
- concerns: コントローラに共通するモジュールやMixin用ファイルを置くフォルダ(オプション).
-
app/jobs: 非同期ジョブ(Active Job)を定義する.
- application_job.rb: 全ジョブの親クラスとなるファイル.
-
app/mailers: メール送信機能を担うMailerクラスを置く.
- application_mailer.rb: 全Mailerの共通クラスとなるファイル.
-
app/models: モデルを配置するディレクトリ. DBテーブルとの対応やビジネスロジックを扱う.
- application_record.rb: Rails 5以降, 全モデルの継承元となる抽象クラス.
- user.rb: ユーザ関連のロジックやDBテーブル(usersテーブル)との関連を定義. (先ほど追加したもの)
- concerns: モデルに共通するモジュールやMixin用ファイルを置くフォルダ(オプション).
-
app/views: ビューテンプレート(HTML, ERBなど)を配置する.
-
layouts: レイアウトファイルを置き, 各ページの共通部分(ヘッダ, フッタ)を定義する.
- mailer.html.erb / mailer.text.erb: メール送信時に使われるHTML形式/テキスト形式のレイアウトテンプレート.
-
layouts: レイアウトファイルを置き, 各ページの共通部分(ヘッダ, フッタ)を定義する.
-
-
3. binディレクトリ
- rails, rake, bundleなどの実行用スクリプトが含まれる.
- docker-entrypoint, setupなど, プロジェクト独自のスクリプトを置く場合もある.
-
4. configディレクトリ
Railsアプリケーション全体の設定関連ファイルが入る.- application.rb: Railsアプリ全体の設定を行うファイル. ミドルウェアやautoloadの設定などを記述する.
- boot.rb: Railsを起動する際に必要な初期化処理を行う.
- cable.yml: Action Cableの設定ファイル.
- credentials.yml.enc / master.key: Railsの認証情報やAPIキーなどを暗号化して管理するためのファイル. master.keyで復号できる.
- database.yml: データベースの接続情報(開発, テスト, 本番環境など)を設定する.
- environment.rb: Railsの初期化プロセスを実行し, config/application.rbを読み込んで起動準備を行う.
- environments: Railsの環境ごとの設定ファイル(development.rb, production.rb, test.rb). ログレベルやキャッシュ設定など.
-
initializers: Rails起動時に読み込ませる設定ファイルの置き場所.
- cors.rb: Cross-Origin Resource Sharing(CORS)の設定.
- filter_parameter_logging.rb: ログに書きたくないパラメータをフィルタする設定.
- inflections.rb: 英単語の単数形/複数形の変換規則を追加変更するときに使う.
- locales: i18nによる国際化対応で使う翻訳ファイル(en.ymlなど).
- puma.rb: デフォルトのアプリケーションサーバPumaの設定ファイル.
- routes.rb: ルーティング(URIパターンとコントローラの対応)を定義するファイル.
- storage.yml: Active Storageの設定(ファイル保存先など).
-
5. config.ru
RackサーバがRailsを起動するときに利用する設定. RailsアプリがRackアプリケーションとして起動されるために必要. -
6. dbディレクトリ
データベースやマイグレーション関連のファイル.-
migrate: マイグレーションファイルを置くディレクトリ. DBのスキーマ変更を管理する.
- 20241225032929_create_users.rbなど, 日付入りのファイル名で作成される. (先ほど追加したもの)
- schema.rb: 現在のDBのスキーマ情報が記録される.
- seeds.rb: 初期データ投入(シードデータ)を定義するファイル.
-
migrate: マイグレーションファイルを置くディレクトリ. DBのスキーマ変更を管理する.
-
7. libディレクトリ
独自のモジュールやタスクなどを配置できる. Rails 6以降ではオートロードパスに含まれないことが多いので, 必要に応じて設定を行う.- tasks: Rakeタスク定義ファイル(*.rake)を置くディレクトリ.
-
8. logディレクトリ
Railsが出力するログファイル(各環境ごとにdevelopment.log, production.log, test.logなど)が格納される. -
9. publicディレクトリ
静的ファイル(HTML, 画像, CSS, JavaScriptなど)を配置する. Railsで直接返せる. -
robots.txtなどがあり, クローラへの指示などを記述できる.
-
10. storageディレクトリ
Active Storage(ファイルアップロード機能)が利用する実際のファイル保存先.- SQLiteのDBファイルがここに置かれているケース(例としてdevelopment.sqlite3など)もあるが, 通常はdbディレクトリや別の場所に配置することが多い.
-
11. testディレクトリ
Railsの標準テストフレームワーク(Minitest)用のファイルを配置する.- channels, controllers, modelsなど, アプリ構造に合わせてテストファイルを分割する.
- fixtures: テストデータを定義し, テストの実行前にDBへ投入する.
- test_helper.rb: テストを実行する際の共通設定やヘルパーメソッドを定義する.
全体の流れとしては, Railsのアプリケーションコード(モデル, コントローラ, ビュー)がappディレクトリに集約され, それらが設定ファイル(config以下)と連携しながら動作する. データベース関連はdb配下で管理し, テスト関連はtestにまとめる. binやlibなども補助的なスクリプトやライブラリを配置する場所として機能している.