コンテンツにスキップ

Ruby on Rails基礎

Ruby on Rails(以下Rails)はRuby構成であるWEB開発のためのMVCフレームワークです。環境構築の説明は割愛。

なおRailsでの開発方法の解説はAPIモード基準です。 MPAでの設計方法は必要になれば追記予定。

参考資料

名称 URL
Rails ガイド https://railsguides.jp/pro
Rails ドキュメント(v6.0) https://railsdoc.com/archive/6_0_2_1/
Rails ガイド API専用アプリケーション https://railsguides.jp/api_app.html
Rails ガイド migrationによるテーブル作成 https://railsdoc.com/page/create_table
Railsで超簡単API https://qiita.com/k-penguin-sato/items/adba7a1a1ecc3582a9c9
Rails params requireとpermitの違い https://techblog.kyamanak.com/entry/2017/08/29/012909
ActiveJobの基礎 Rails ガイド https://railsguides.jp/active_job_basics.html
Rails+RSpecで気軽に始めるテスト https://weseek.co.jp/tech/1409/

1. Railsの基本知識と概念

1.1. 基本知識と特徴

Ruby on Railsは2004年にデンマークのプログラマであるデイヴィッド・ハイネマイヤー・ハンソン(通称DHH)氏によって作られたフレームワークです。 「MVCアーキテクチャ」に基づいて構築されたフレームワークであることが特徴です。 それぞれ、Model(モデル)View(ビュー) Controller(コントローラ)の頭文字をとって名付けられています。

MVC(R含む)の解説

モデル 説明 実装内容
Model データベースとのやり取りや処理の管理をする仕組み DBの読み書き, システム処理
View サイトの見た目(MPA)を提供する仕組み フロントエンド
Controller Modelからデータを受け取りviewにレンダリングする仕組み ModelとViewの連携
Routing URLとアプリケーションのパラメータを結びつける仕組み(ルータ) ルーティング構築

RailsをMPA構成で開発する場合、Routing → Controller → Viewという順で処理が行われます。

1.2. Railsの基本操作と構造

基本操作とコマンド

Railsプロジェクトの新規作成(APIモード(MPAの場合は--apiを除外))

rails new プロジェクト名 --api
オプション 説明 
--api APIモード
-d データベースの指定(ない場合はsqlite3となる):指定可能(mysql, postgresqlなど)

Railsサーバの起動(注意:rails db:migrateがないと立ち上がりません=> DBを設定する必要がある)

rails s オプション
立ち上がるポート番号の変更はconfig/puma.rbで設定する、もしくはオプションで。

オプション 説明 使用例
-e 環境(開発 production/本番 test)の指定 rails s -e production
-p 立ち上げるポート番号の指定 rails s -p 3001

DB変更は以下のように実装。

  • Rails(v 6.0.0系)では以下コマンドでできる(例ではpostgreSQL)
rails db:system:change --to=postgresql
  • もしくは以下の方法。
  • Gemfile内のsqlite3をそれぞれのDBに変更(変更後もちろんbundle install)
  • データベース設定(config/database.yml)で設定

ディレクトリ構成

親ディレクトリ サブディレクトリ 説明
app/ アプリケーションを格納する。主要なプログラムはこの配下に格納。
assets/ スタイルシートや画像などを格納するディレクトリ
assets/images/ スタイルシートや画像などを格納する
assets/javascript/ JavaScriptのスクリプトを格納する
assets/stylesheets/ スタイルシートを格納する
controllers/ コントローラを格納する
controllers/application_controller.rb アプリケーションで共通のコントローラ
helpers/ ヘルパーを格納する
helpers/application_controller.rb アプリケーションで共通のヘルパー
models/ モデルを格納
viewa/ ビューを格納する
views/layouts/ ビューのレイアウトとして使用するRHTMLテンプレートを格納するディレクトリ
views/layouts/application.html.erb アプリケーションで共通のレイアウト
bin/ バイナリ実行可能ファイルの格納(触る必要ない)
config/ プロジェクトの設定ファイルを格納
environments/ 環境単位の設定ファイルを格納する
initializers/ 初期化ファイルを格納する
locales/ 辞書ファイルを格納する
db/ データベースの設定ファイルの格納
migrate/ マイグレーションファイルを格納
doc/ ドキュメントを格納
lib/ 複数のアプリケーション間で共有するライブラリを格納する
assets/ 自分で生成したライブラリを格納する
tasks/ 自分で生成したRakefileを格納する
log/ ログファイルが格納される
public/ Web上に公開するファイルを格納する
script/ 開発に役立つプログラムを格納
test/ アプリケーションのテストに使うファイルを格納
tmp/ キャッシュなど、一時的なファイルを格納
vendor/ ライブラリや他のアプリケーションで共有するような外部ライブラリを格納
rails/ rails:freeze:gemsタスクでバージョンを固定したRailsを格納
plugins/ プラグインを格納
config.ru Rackの設定
Gemfile gemの依存関係を指定できる
Rakefile ターミナルから実行可能なタスク
readme.md Read.me

1.3. マイグレーション(migrate)

マイグレーション: 直接SQLを使わずにデータベースのテーブルやカラムなどの構造を変更/定義できるもの

マイグレーションファイルはdb/migrateフォルダの下に作成される。

以下コマンドを行うと、マイグレーションファイルに書いてある指示通りにテーブルが作られます。

rails db:migrate

マイグレーションファイルで指示した構造以外に3つのカラム(id, created_at, updated_at)が自動で生成される。

マイグレーションを利用したDB設計/設定の参考URL:https://railsdoc.com/archive/6_0_2_1/migration

Railsで生成するDBに初期データを入れる方法:https://qiita.com/mHadate/items/bc698ce5c126c932487e

Railsで使用できるデータの型

内容
string 文字列(255文字まで)
text 長い文字列(256文字以上)
integer 整数
float 浮動小数
decimal 精度の高い小数
datetime 日時
timestamp タイムスタンプ
time 時間
date 日付
binary バイナリデータ
boolean Boolean

1.4. Model

モデル(Active Record)はアプリケーションが扱うデータや処理を表現するもの。 データベースへの読み書きを行う場合、このModelを使います。

rails g model モデル名

モデルに関するファイルや変数などの命名規則

種類 説明
モデル名 先頭は大文字で単数形 User
ファイル名 先頭は小文字で単数形 user.rb
テーブル名 先頭は小文字で複数形 users
テストスクリプト名 xxx_test.rb user_test.rb

モデルの生成

モデル名.new([属性])

実装例1(comment.rb)

class CommentsController < ApplicationController

  def index
    @comments = Comment.all.order("created_at DESC")
    @comment = Comment.new
  end

  def create
    # このcreateアクションの書き方は非推奨です。
    @comment = Comment.create!(comment_params)
    redirect_to root_path
  end

  private

  def comment_params
    params.require(:comment).permit(:text)
  end
end

その他のモデル(一部)

モデル 説明 使用例
モデル.find_by(条件) 条件に一致した最初の1件を取得(存在しない場合の返り値はnil) Page.find_by(category_id: 1)
モデル.find(件数) IDを指定してレコードを取得(複数指定も可能)
モデル.find_each(オプション) ... 大きなデータをもつモデルなどを処理する時に使う 詳細はRailsドキュメントにて
モデル.find_in_bacthes(オプション) ... 分割してレコードを処理する 詳しくはRailsドキュメントにて
モデル.find_or_create_by(条件) 条件を指定して初めの1件を取得し、1件もなければ作成
モデル.find_by_sql(SQL文) SQLを直接使って取得
モデル.all すべてのレコードを取得
モデル.first(件数) 最初のレコードを取得
モデル.last(件数) 最後のレコードを取得(取得は最後から)
モデル.where(条件) 条件に当てはまるレコードを全て取得 詳細な使い方はRailsドキュメントにて
モデル.rewhere(条件) 条件に当てはまるレコードを上書き
モデル.group(グループ化キー) 取得した値をグループ化
モデル.order(:キー名 [ :並び順]) 取得したレコードの並び替え[昇順: ASC, 降順: DESC]

まだまだたくさんあります。 詳しくは:https://railsdoc.com/archive/6_0_2_1/model

モデルの削除(Consoleにて)

rails destroy model モデル名

Rails Consoleと組み合わせ使用することでConsole上でもModelを使用可能。

モデルとマイグレーションの違い

  • migrationファイル→DBに変更を加える内容
  • modelファイル→DBとRailsのアプリケーションを繋ぐ

基本モデルの生成にはrails g modelを途中で生成したDBに変更を加える場合にマイグレーションファイルを使用する。

migrateファイルの中の設定例(カラム名は小文字英語)

create_table :titles do |t|
  t.データ型 :カラム名(, オプション)
end

なおidとデータ生成時刻created_at(t.timestampsによる)は自動生成される。

データ構造に条件を付ける例(デフォルト値やNot nullの設定)

def change
  create_table :titles do |t|
      t.string :name, :null => false
      t.integer :old, :default => 10
      t.string :address, :null => false, :default => 'Tokyo'
      t.integer :reference, :foreign_key => true # 外部キー制約
      t.string :description, :limit => 1024 # string型にlimitをつければ最大文字数

      t.timestamps # 生成時刻/更新時刻のためのカラムcreated_at、update_atの追加
  end
end

データベースの設定(生成するdbの種類や環境下設定)はintalizers/database.ymlで行う。

1.5. View(erb)

ReactのJSXやTSXに似ている。HTMLの中にRubyが埋め込めるもの。

ビューからコントローラのインスタンス変数には@変数名でアクセス。

コード 説明
<% %> 出力しないコード
<%= %> 結果の出力
<%== %> 結果をエスケープしないで出力
<% -%> 後ろの改行を取り除く
<%- %> 行頭の空白削除
<%# %> コメント

1.6. Controller

コントローラはモデルからデータを受け取りビューにレンダリングするためのもの。

rails g controller コントローラ名

特徴 * コントローラには複数のアクションが含まれている * コントローラの名前の付け方には決まりがある

Controllerの命名規則

  • 英大文字から始まる
  • 英数字のみ
  • パスカルケース
  • ファイルはapp/controllerディレクトリに格納
  • ファイル名はコントローラ名の単語区切りを「_」にし、すべて小文字

ひな形

class コントローラ名Controller < ApplicationController
  def メソッド名
  end
edn

URLから送られたパラメータは以下で取得(PostとGet(クエリパラメータ)の取得が可能)

params[:パラメータ名]

アップロードされたファイルデータの取得

=begin
  ファイル名の取得例
=end
params[:パラメータ名].original_filename
付けるもの 説明
.original_filename ファイル名
.content_type コンテンツタイプ
.size サイズ
.read ファイル本体の読み込み

1.7. Routing

ルーティングはURLとアプリケーションのパラメータを結びつけるためのもの。 config/routes.rbにて設定を行う。優先順位は上に書かれているものから。

詳しくはhttps://railsdoc.com/archive/6_0_2_1/routes

下記rakeコマンドでルーティングの確認が可能

rake routes

リソースのルーティング

resources(:リソース名 [, オプション])
オプション 説明
:as ルート名に利用する別名
:controller コントローラを指定
:path_names 指定したアクションのみ名前の変更
:path URLを書き換える
:only 生成されるURLを絞り込む(受け付けるHTTPメソッドも指定可能)
:except 指定したURLは生成しない
:shallow ルーティングを複雑化しない
:shallow_path 指定したパラメータを先頭に追加
:shallow_prefix 指定したパラメータを名前付きルーティングとして先頭に追加
:format フォーマット指定
:param パラメータを上書き

REST APIの例

resources :pages
#     pages GET    /pages(.:format)          pages#index
#           POST   /pages(.:format)          pages#create
#  new_page GET    /pages/new(.:format)      pages#new
# edit_page GET    /pages/:id/edit(.:format) pages#edit
#      page GET    /pages/:id(.:format)      pages#show
#           PUT    /pages/:id(.:format)      pages#update
#           DELETE /pages/:id(.:format)      pages#destroy

処理するコントローラの指定例

resources :pages, controller: :mains

ルートのURLの指定

root(パス, [オプション])

pagesコントローラとindexアクションをroot指定

root controller: 'pages', action: 'index'
# root  / pages#index

名前空間(namespaceのグループ化)の付与

namespace モジュール名 [, オプション] do
  ルート定義
end
オプション 説明
:path ルートのパスを指定
:module namespaceを指定
:as ルート名に使用する別名
:shallow_path 指定したパラメータを先頭に追加

userにadminの名前空間の付与例

namespace :admin do
  resources :user
end
# admin_user_index GET    /admin/user(.:format)          admin/user#index
#                  POST   /admin/user(.:format)          admin/user#create
#   new_admin_user GET    /admin/user/new(.:format)      admin/user#new
#  edit_admin_user GET    /admin/user/:id/edit(.:format) admin/user#edit
#       admin_user GET    /admin/user/:id(.:format)      admin/user#show
#                  PUT    /admin/user/:id(.:format)      admin/user#update
#                  DELETE /admin/user/:id(.:format)      admin/user#destroy

1.8. GemFile

Railsで使用するGemの依存関係を管理するファイル。

詳しくはhttps://railsdoc.com/archive/6_0_2_1/gem

記入例

gem 'rails7', '3.2.1'

開発モードとプロダクションモードでのgemのインストールは下記のように設定。

# 上が開発モード、下がプロダクションモードでのgem利用
gem 'sqlite3', '~> 1.4', group: :development
gem 'pg', group: :production

基本的ワークフローとしては Gemfileに必要なgemを追記した場合はbundle install、バージョン変更などをした場合はbundle update

コマンド 説明
bundle install 依存ライブラリのインストール
bundle update 依存ライブラリのアップデート
bundle package 依存ライブラリを「vender/cache」以下にまとめる
bundle check 依存ライブラリがインストールされているかチェック
bundle list インストールされているライブラリの一覧
bundle show gemファイルのソースのパスを表示
bundle init gemを初期化

1.9. Rakeコマンド

Rubyで記述されたビルドツール。 Rails5以降はrailsコマンドでも呼び出し可能。

2. その他の実装

2.1. アソシエーション

参照元テーブルから参照先テーブルを参照するための設定

https://railsdoc.com/archive/6_0_2_1/association

2.2. アクション後の処理実行の実装

アクションの後に処理を実行

after_action(アクション名 [, オプション])
オプション 説明
:only 実行するアクション
:except 実行しないアクション
:if 実行する条件を指定
:unless 実行されない条件を指定

アクション後の処理の実行

after_action :store_location
def store_location
  if request.fullpath !~ Regexp.new('\\A/users/.*\\z') && !request.xhr?
    session[:previous_url] = request.fullpath
  end
end

https://railsdoc.com/archive/6_0_2_1/callback

2.3. クッキー・キャッシュの扱い

キャッシュ

キャッシュはユーザがアクセスする際のレスポンス最適化に使える。 キャッシュには以下の種類がある。

  • ページキャッシュ
  • アクションキャッシュ
  • フラグメントキャッシュ
  • ロシアンドールキャッシュ
  • 低レベルキャッシュ
  • SQLキャッシュ

キャッシュの保存場所 * メモリ * ファイル * memcached

クッキーを保存

Cookieの保存

cookies[:クッキー名] = { key: クッキー情報 }

https://railsdoc.com/archive/6_0_2_1/cookie_cache

2.4. バリテーションの実装

データベースへのデータ保存前に保存するデータが要件(正しいもの)かどうかをバリテーションを用いて実装する。

属性の値が一意であることをバリデーションできる。 バリテーションはmodelまたはmigrationファイルに記載する。

https://railsdoc.com/archive/6_0_2_1/validation

2.5. アクティブジョブ

アクティブジョブはジョブを宣言し、それによりバックエンドでさまざまな方法によるキュー操作を実行するための機能。 バックグラウンドで実行するジョブの作成、キュー登録 (enqueue)、実行が可能です。

参考記事: https://qiita.com/petertakahashi/items/cb9ae73e5ba3020f4a89

アクティブジョブで実装される機能は基本的にリアルタイム性を伴わない場合や重い処理に使われることが多い。

  • メールの送信
  • 画像の処理
  • データを集計してCSVに落とす

など

rails generate job ジョブ名

上記を実行するとapp/jobs下にジョブが1つ作成される。 --queue urgentをオプションで付けるとジョブが1つ作成される。

生成されたジョブの雛型

class GuestsCleanupJob < ApplicationJob
  queue_as :default

  def perform(*guests)
    # 後で実行するタスクをここに置く
  end
end

生成されたジョブを実行(キュー登録)

rails consoleで行える。 上記ジョブ名の場合

GuestsCleanupJob.perform_later (引数があればここに記述)

各場合

# 明日正午に実行したいジョブをキューに登録する
GuestsCleanupJob.set(wait_until: Date.tomorrow.noon).perform_later
# 一週間後に実行したいジョブをキューに登録する
GuestsCleanupJob.set(wait: 1.week).perform_later

productionモードにおけるアクティブジョブ

Rails自体が提供するのは、ジョブをメモリに保持するインプロセスのキューイングシステムだけです。 そのためproductionモードでは別途キューイングのバックエンドを用意する必要があります。

3. Railsにおけるテスト

テストの予備知識

テストを行う理由は以下の確認のため。 * あるURLにアクセスした際に、予期した画面が表示されるか * ある正しい操作をした際に、アプリケーションの状態が正しく変更されるか * ある正しくない操作をした際に、適切なエラーメッセージが表示されるか

テストには「単体テスト(機能テスト)」、「統合(複合)テスト」、「総合テスト」がある。

単体テスト(機能テスト)

機能のテスト。

  • モデルの検索系メソッドが正しい値を取得できるか
  • モデルの更新系メソッドが正しくデータベースを更新できるか
  • モデルの更新系メソッドが不正な入力に対して、適切なエラーを発生させるか
  • 更新系のアクションが正しくデータベースを更新されるか

総合テスト

  • ログインして、新しいメンバーを追加して、ログアウトするといった一連の動きをテスト など。

テストツールにはgem「Rspec」を使うことを勧める。

4. Rails開発に便利なGem一覧

よく使いそうなgemを記載しておきます。

gem名 種類 説明
devise 認証系 ユーザ認証の基本機能を提供
devise_token_auth 認証系 トークン認証を実現するもの
dotenv-rails 未分類 環境変数(.env)を扱うことが出来るようになる
omniauth 認証系 SNS認証の実装に使える
rack-cors 未分類 CORSの制御機能を追加するもの
rspec-rails ツール テストツール
cancancan 認証系 ユーザーの権限管理をしたいときに使える、deviceと混ぜるとよい
sidekiq-scheduler 定期実行系 cronのようにジョブを定期的に実行(Sidekiqの拡張)
whenever 定期実行系 crontab管理ライブラリ(cron必須)

deviceで実現できる機能

  • ユーザー登録
  • ログイン/ログアウト
  • 登録情報の編集
  • パスワード変更、再発行

sidekiq-schedulerに関して

Sidekiq:Rubyとは異なるプロセスをバックグラウンドで実行するためのキューイングジョブ処理の仕組み。

sidekiq-schedulerはSidekiqの拡張gemでcronのようにジョブを定期的に実行できる。

参考URL:https://zenn.dev/yoiyoicho/articles/538af41a66867d

5. APIモードにおける実装メモ

5.1. Active Record(model)関係

whereメソッドにおける比較演算(<, >, <=, >=)に関して

一般的にwhereメソッドにおいて比較によりデータを抽出する場合のパターンをいくつか記載。

whereメソッドの返り値はActiveRecord::Relationなのでチェーン状にメソッドを記述できます。

通常の書き方

User.where('id >= ?', 100)
# 100以上のidのレコードを取得

範囲演算子を使った書き方(より大きい >のみは範囲オブジェクトで記述不能)

# 10以上(>=)のidのレコードを取得
User.where(id: 10..)
# 10以下(<=)のidのレコードを取得
User.where(id: ..10)
# 10未満(<)のidのレコードを取得
User.where(id: ...10)

5.5. その他rails設定

Railsで時間(日時など)を取得する場合に関して

Date.todayはRuby自体のものでENV(環境変数)やシステム(OS)のタイムゾーンを参照する。

Date.currentはapplication.rbのタイムゾーンを用いる => Railsで設定可能

結論Railsで制御が効くのでDate.currentを使おう。

application.rbには以下のように設定すればいい(抜粋)

# JPT(東京時刻)に設定
config.time_zone = 'Tokyo'
# データベースへのデータ保存時刻をconfig.time_zoneに合わせる
config.active_record.default_timezone = :local