Ruby on Railsとは
Ruby on Rails(Rails)はRubyでWebアプリケーションを作るためのフレームワークです。URLを受け取り、必要なデータを処理し、HTMLやJSONを返すまでの共通部分を用意してくれます。
- 設定より規約:よくある名前やファイル配置を守ると、設定を減らせます。
- DRY:同じ知識を複数の場所へ重複して書かず、変更箇所を一つにします。
Railsの学習では、魔法のように見える自動処理を丸暗記するより、ブラウザーからのリクエストがルート、コントローラー、モデル、ビューを通る順番を確認することが大切です。
学習前の準備
RubyとRailsのバージョンを確認します。プロジェクトの中では、インストール済みのRailsではなく、プロジェクトが指定したbin/railsを使います。
ruby --version
rails --versionruby 3.3.6
Rails 8.0.2表示される細かなバージョンは環境によって異なります。Rails 8を使えることを確認し、エディターとターミナルを用意してください。データベースは最初は標準構成のSQLiteで進められます。
bin/railsを実行します。アプリケーションを作る
rails newでアプリケーションの土台を作ります。ここでは記事を管理するrails_notesを作成します。
rails new rails_notes
cd rails_notes
bin/rails db:prepare
bin/rails serverhttp://localhost:3000ブラウザーでRailsの初期画面が表示されれば、Ruby、Rails、依存ライブラリ、サーバーが連携しています。サーバーを止めるときはターミナルでCtrl+Cを押します。
主なディレクトリー
app/controllers/ リクエストを処理するコントローラー
app/models/ データとルールを扱うモデル
app/views/ HTMLなどの表示テンプレート
config/routes.rb URLと処理の対応
db/migrate/ テーブル変更の履歴
config/database.yml データベース設定最初から全ファイルを覚える必要はありません。自分で追加したファイルがどの役割に属するかを、ディレクトリー名から判断できるようにしましょう。
MVCで役割を分ける
Railsは主にModel、View、Controllerの3つに処理を分けます。Controllerは依頼を受け、Modelからデータを取得し、Viewへ渡します。Viewは表示を担当し、Modelはデータとそのルールを担当します。
ブラウザー
↓ GET /articles
routes.rb
↓ ArticlesController#index
モデル Article からデータを取得
↓
app/views/articles/index.html.erb でHTMLを作成
↓
ブラウザーへレスポンスControllerにHTMLを書いたり、Viewにデータベース検索を書いたりすると、後で修正しにくくなります。小さな例でも役割を分ける習慣を身につけましょう。詳しいルーティングと画面の作成はMVCとルーティングで確認できます。
ルーティングと画面
config/routes.rbには、HTTPメソッド、URL、コントローラーのアクションを登録します。まず固定の文字列を表示して、URLから処理へ到達することを確かめます。
Rails.application.routes.draw do
root "pages#home"
get "/about", to: "pages#about"
endclass PagesController < ApplicationController
def home
@message = "Railsへようこそ"
end
def about
end
end<h1><%= @message %></h1>
<p>最初のRails画面です。</p>Railsへようこそ
最初のRails画面です。同じ画面を作るときも、まずルートを追加し、次にアクション、最後にビューを作ると、どこが不足しているかを確認しやすくなります。
モデルとデータベース
モデルを生成すると、Rubyのクラスとテーブル変更の設計図であるマイグレーションが作られます。マイグレーションを実行して初めてデータベースへ反映されます。
bin/rails generate model Article title:string body:text published:boolean
bin/rails db:migratebin/rails console
article = Article.create!(title: "最初の記事", body: "Railsを学んでいます", published: true)
article.title
# => "最初の記事"
Article.count
# => 1db:migrateは、マイグレーションに書かれた変更を適用します。既に適用したマイグレーションを書き換えず、新しい変更は新しいマイグレーションとして追加します。詳しい検索・関連付け・バリデーションはActive Recordとデータベースで学べます。
CRUDを一周する
データを扱う基本操作は、Create(作成)、Read(読み取り)、Update(更新)、Delete(削除)の4つです。RailsではActive Recordのメソッドでこの操作を表現できます。
# Create
article = Article.create!(title: "入門", body: "本文")
# Read
Article.all
Article.find(article.id)
Article.where(published: true)
# Update
article.update!(title: "更新した入門")
# Delete
article.destroy!Article.where(published: true).pluck(:title)
# => ["最初の記事", "入門"]実際の画面では、一覧にArticle.all、詳細にArticle.find(params[:id])のような処理を置きます。IDが存在しない場合のエラーや、削除前の確認も考える必要があります。
バリデーションでデータを守る
フォームから受け取る値は、空欄や長すぎる文字列を含む可能性があります。モデルにルールを書き、保存前に確認します。
class Article < ApplicationRecord
validates :title, presence: true, length: { maximum: 100 }
validates :body, presence: true
endarticle = Article.new(title: "", body: "本文")
article.valid?
# => false
article.errors.full_messages
# => ["Title can't be blank"]saveは失敗するとfalseを返し、save!は例外を発生させます。画面からの入力では失敗を画面へ戻し、バッチ処理では例外を記録するなど、場面に応じて使い分けます。
フォームから保存する
フォームは表示だけでなく、送信先のルート、コントローラーの処理、入力値の許可が必要です。Railsのフォームヘルパーを使うと、CSRF対策用のトークンも組み込まれます。
resources :articlesdef create
@article = Article.new(article_params)
if @article.save
redirect_to @article, notice: "記事を作成しました"
else
render :new, status: :unprocessable_entity
end
end
def article_params
params.require(:article).permit(:title, :body, :published)
end<%= form_with model: @article do |form| %>
<%= form.label :title, "タイトル" %>
<%= form.text_field :title %>
<%= form.label :body, "本文" %>
<%= form.text_area :body %>
<%= form.submit "保存" %>
<% end %>permitを忘れると、Railsは受け取った属性をそのままモデルへ渡しません。許可する項目を明示するStrong Parametersは、フォームを作るときの必須手順です。
安全なアプリにする
入力値をHTMLへ表示するときは、通常のERB出力<%= ... %>を使います。文字列をHTMLとしてそのまま出力する<%== ... %>やhtml_safeは、内容を十分に検証できる場合だけに限定します。
- フォームの属性をStrong Parametersで限定する
- モデルのバリデーションを画面側のチェックだけに任せない
- 認証と認可を分け、他人のIDを指定した操作を許さない
- 秘密情報をソースコードへ直接書かず、環境変数やCredentialsを使う
開発中に表示されるエラー画面には内部情報が含まれることがあります。公開環境では設定を確認し、ログへパスワードやトークンを書き出さないようにします。
Gemfileと依存関係
Railsアプリで使うgemはGemfileへ記録し、Bundlerでプロジェクト単位にインストールします。誰かの環境で動いたgemを手作業で追加するのではなく、ファイルとロックファイルを共有することで同じ環境を再現できます。
gem "rails", "~> 8.0"
gem "sqlite3"
gem "bcrypt", "~> 3.1"
group :development, :test do
gem "debug"
endbundle install
bin/rails about
bundle exec ruby -vCould not find gem ... # 依存関係の問題がある場合
Rails version: 8.0.2
Ruby version: 3.3.6バージョンを変えたらGemfile.lockも確認します。アプリ内ではbin/railsを使い、必要に応じてbundle execでプロジェクトのgemを指定します。
環境変数とCredentials
APIキーや本番用のパスワードはソースコードへ直接書きません。ローカルの一時的な設定には環境変数、Railsが暗号化して管理する設定にはCredentialsを使います。
api_key = ENV.fetch("WEATHER_API_KEY")
legacy_key = ENV["WEATHER_API_KEY"]
puts api_key.lengthWEATHER_API_KEY="local-test-key" bin/rails runner 'puts ENV.fetch("WEATHER_API_KEY").length'bin/rails credentials:edittoken = Rails.application.credentials.dig(:weather, :api_key)
raise "設定がありません" if token.blank?Credentialsの暗号化ファイルと復号に必要な鍵は、役割が違います。暗号化ファイルをGitで管理する場合も、master.keyや本番の鍵は秘密として扱います。
練習問題
問題1:トップページを作る
PagesController#homeを作り、/で「今日の学習」を表示してください。
# config/routes.rb
root "pages#home"
# app/controllers/pages_controller.rb
def home
@title = "今日の学習"
end
# app/views/pages/home.html.erb
<h1><%= @title %></h1>今日の学習問題2:公開記事だけ検索する
公開済みの記事だけを新しい順に取得するActive Recordのコードを書いてください。
articles = Article.where(published: true).order(created_at: :desc)
puts articles.map(&:title)問題3:タイトル必須を確認する
タイトルが空のArticleを作り、保存できないこととエラーメッセージを確認してください。
article = Article.new(title: "", body: "本文")
puts article.valid?
puts article.errors.full_messagesfalse
Title can't be blank次に学ぶこと
公式のGetting Started with Railsも参照し、手元のアプリでコマンドを実行しながら学習を進めてください。
