Rails Wayとは何か
Rails Wayとは何か
Ruby on Railsを使った開発において、「Rails Way」という言葉をよく耳にします。
今までは何となくRails Wayを「Railsの提供する機能のみを使って開発する」くらいに理解していましたが、この記事では改めてRails Wayとは何かについて言語化してみました。
Railsの誕生とDHH
Rails Wayを理解するには、まずRailsの誕生背景を知る必要があります。
Ruby on Railsは2004年、David Heinemeier Hansson(通称: DHH)によって生み出されました。
DHHは当時、Basecampというプロジェクト管理ツールを開発していました。その開発過程で、Webアプリケーション開発に共通する繰り返し作業の多さに気づき、これを効率化するためのフレームワーク「Ruby on Rails」を開発し、2004年に発表しました。
Rails Wayの原則
1. DRY(Don't Repeat Yourself)
Rails Wayの最も重要な原則の一つが「DRY」です。これは「同じことを繰り返し書くな」という意味で、コードの重複を避けることを指します。
Railsでは、このDRYの原則を実現するための仕組みが多数用意されています。
Concernの活用
共通処理は Concern として実装することでコードの重複を避けることができます。
# app/models/concerns/timestampable.rb
module Timestampable
extend ActiveSupport::Concern
included do
scope :recent, -> { order(created_at: :desc) }
scope :today, -> { where(created_at: Date.current.all_day) }
end
def formatted_created_at
created_at.strftime("%Y年%m月%d日")
end
end
# 複数のモデルで共通の機能を再利用
class Article < ApplicationRecord
include Timestampable
end
class Comment < ApplicationRecord
include Timestampable
end
Scopeの活用
Controller 側で毎回 where の条件を書くのではなく、scopeとして定義することで Controller 側の処理をシンプルに保つことができます。
class User < ApplicationRecord
# 共通のクエリロジックを一箇所で定義
scope :active, -> { where(status: 'active') }
scope :admin, -> { where(role: 'admin') }
scope :recent, -> { order(created_at: :desc) }
end
# 呼び出し側はシンプルに
User.active.admin.recent.limit(10)
コールバックの活用
Controller内で共通で行われる事前処理などはコールバックとして実装し、action内ではaction固有の処理のみを実装していきます。
class ApplicationController < ActionController::Base
# 全てのコントローラで共通する認証処理
before_action :authenticate_user!
before_action :set_current_user
private
def set_current_user
Current.user = current_user
end
end
class ArticlesController < ApplicationController
# 特定のアクション前に実行される共通処理
before_action :set_article, only: [:show, :edit, :update, :destroy]
before_action :check_owner, only: [:edit, :update, :destroy]
def show
# @articleは既にset_articleで設定済み
end
def edit
# @articleの設定とowner確認は既に完了
end
private
def set_article
@article = Article.find(params[:id])
end
def check_owner
redirect_to root_path unless @article.user == current_user
end
end
View Helperの活用
View Helperを活用することで、View内に表示のための複雑な分岐処理などを書く必要がなく、Viewをシンプルに保つことができます。
# app/helpers/application_helper.rb
module ApplicationHelper
# 繰り返し使われるHTMLの生成を共通化
def page_title(title = nil)
base_title = "My App"
title.present? ? "#{title} | #{base_title}" : base_title
end
def flash_message_class(type)
case type.to_sym
when :notice then "alert-success"
when :alert then "alert-danger"
when :warning then "alert-warning"
else "alert-info"
end
end
def format_datetime(datetime)
return unless datetime
datetime.strftime("%Y年%m月%d日 %H:%M")
end
end
# ビューファイルでの使用例
# app/views/layouts/application.html.erb
<%= content_for :title, page_title(@page_title) %>
<% flash.each do |type, message| %>
<div class="alert <%= flash_message_class(type) %>">
<%= message %>
</div>
<% end %>
<p>投稿日時: <%= format_datetime(@article.created_at) %></p>
2. 設定より規約(Convention over Configuration)
Rails Wayのもう一つの重要な原則が「設定より規約」です。
これは、開発者が決めなければならない設定を最小限に抑え、代わりに合理的なデフォルト値や命名規約を提供するという考え方です。
例えば:
-
User
モデルは自動的にusers
テーブルにマッピングされる -
UsersController
のindex
アクションはapp/views/users/index.html.erb
テンプレートを探す - 外部キーは
user_id
という命名規約で自動的に関連付けられる
これにより、開発者は本来の業務ロジックに集中できます。
他の言語・フレームワークとの比較
多くの言語やフレームワークでは、アーキテクチャの設計から始める必要があります。
しかし、Rails Wayがあることで、Railsではこの段階を大幅に短縮できます。
アーキテクチャを考える必要がない
-
Java + Spring
DIコンテナの設定、レイヤーの分割、設定ファイルの管理など、開発開始前に多くの設計決定が必要 -
Python + Django
設定ファイルの構成、URLルーティングの設計、アプリケーション構造の決定が必要 -
Rails
MVCの基本構造が決まっており、すぐにビジネスロジックやUIの実装に着手できる
0→1からIPOの規模までサポート
Railsは0→1のプロトタイプ開発から、IPOレベルの規模までサポートしており、Rails Wayに従うことでどのステージでも最速で開発ができます。
-
プロトタイプ段階
迅速に機能を実装し、アイデアを形にできる -
スタートアップ段階
少ないリソースで多くの機能を実装できる -
エンタープライズ段階
GitHub、Shopify、Airbnbなど大規模サービスでも実証済み
Rails Wayのメリット
1. 開発効率の最大化
Rails Wayに従うことで、以下のような効果が得られます。
-
早く少ないコード量で開発
定型的なコードはジェネレーターで自動生成 -
意思決定の削減
規約に従うことで、細かな設計判断に時間を取られない -
保守性の向上
一貫したコード構造により、バグの発見と修正が容易
2. チーム開発での優位性
Rails Wayの規約により、以下のような利点があります。
-
早いキャッチアップ
Rails経験者であれば、どのRailsアプリケーションでも基本構造は同じなので、最も重要な業務ロジックの理解という部分にすぐに入れる -
コードレビューの効率化
共通の規約により、レビューのポイントが明確 -
属人化の回避
個人の好みではなく、フレームワークの規約に従うため、コードの一貫性が保たれる
Rails Wayから逸脱するとどうなるか
保守性の低下
Rails Wayから外れたコードは、以下のような問題を引き起こします。
1. 規約に従わない命名
# ❌ Rails Wayに従わない例
class UserInformation < ApplicationRecord
self.table_name = 'user_data'
self.primary_key = 'user_data_id'
belongs_to :account, foreign_key: 'account_data_id'
end
# ✅ Rails Wayに従った例
class User < ApplicationRecord
# テーブル名: users(自動)
# 主キー: id(自動)
belongs_to :account # 外部キー: account_id(自動)
end
2. Fat Controllerの問題
# ❌ Rails Wayに従わない例(Fat Controller)
class UsersController < ApplicationController
def create
@user = User.new(user_params)
# コントローラにビジネスロジックが混在
if @user.email.present? && @user.email.include?('@')
@user.email = @user.email.downcase
if @user.password.length >= 8
@user.password_digest = BCrypt::Password.create(@user.password)
if @user.save
# メール送信ロジックもコントローラに
UserMailer.welcome_email(@user).deliver_now
# ポイント付与ロジックもコントローラに
@user.update(points: 100)
redirect_to @user, notice: 'ユーザーが作成されました'
else
render :new
end
else
@user.errors.add(:password, 'は8文字以上である必要があります')
render :new
end
else
@user.errors.add(:email, 'は有効な形式である必要があります')
render :new
end
end
end
# ✅ Rails Wayに従った例(Skinny Controller)
class UsersController < ApplicationController
def create
@user = User.new(user_params)
if @user.save
redirect_to @user, notice: 'ユーザーが作成されました'
else
render :new
end
end
private
def user_params
params.require(:user).permit(:email, :password, :name)
end
end
# モデルにビジネスロジックを配置
class User < ApplicationRecord
has_secure_password
validates :email, presence: true, format: { with: URI::MailTo::EMAIL_REGEXP }
validates :password, length: { minimum: 8 }
before_save :normalize_email
after_create :send_welcome_email, :grant_initial_points
private
def normalize_email
self.email = email.downcase if email.present?
end
def send_welcome_email
UserMailer.welcome_email(self).deliver_now
end
def grant_initial_points
update_column(:points, 100)
end
end
設計思想の衝突
Railsは「あえて密結合」を選んだフレームワークです。
これは、DDD(ドメイン駆動設計)のようなレイヤードアーキテクチャとは異なる設計思想です。
-
DDD/レイヤードアーキテクチャ
責務を疎結合に設計し、ドメインロジックを独立させる -
Rails Way
データアクセスやビジネスロジック、バリデーションまで全て同一モデルに配置し、あえて密結合にしている
異なる設計思想のアーキテクチャを採用する場合は、以下を理解する必要があります。
- Rails Wayの恩恵を受けられなくなる可能性がある
- 追加の複雑性を管理する必要がある
- チームメンバーの学習コストが増加する
- 保守性と開発効率のトレードオフを受け入れる覚悟が必要
まとめ
この記事ではRuby on Railsは開発者のDHHの思想に強く影響を受けていることや、Rails Wayに従って開発をすることで多くの恩恵を受けられることを紹介しました。
Rails Wayに乗って、最速で開発していきましょう💪
Discussion