✂️
【Rails】脱・ifネスト地獄!ビューをスッキリさせる2つのテクニック
はじめに
Rails アプリを開発していると、ビューで複数の条件分岐(if/elsif/else)が深くネストし、コードが読みづらくなることがあります。特に Slim のようなインデントベースのテンプレートでは、ネストが深まるほど視認性が低下し、メンテナンス性も悪化します。
本記事では「元の仕様を変えず」「Slim+Rails標準機能だけで」可読性を高める方法を2つ紹介します。
問題のコード例
以下は「注文(Order)」モデルの状態に応じてボタンを切り替える深いネスト例です。
3段階以上の入れ子になっているため、条件が増えると「なにを表示しているのか」が一目でわかりません。
.order-actions
- if order.pending?
- if order.expedited?
- if order.insurance_added?
= link_to urgent_shipping_order_path(order), class: "btn btn-danger" do
| 急便を手配
- elsif order.paid?
.btn.btn-secondary.disabled
| 支払い完了
p.note
| ※ 支払い後に出荷手続きを行います
- elsif order.shipped?
= link_to track_order_path(order), class: "btn btn-info" do
| 発送状況を確認
- else
= link_to order_receipt_path(order), class: "btn btn-success" do
| 領収書を見る
アプローチ1: Partialに切り出す
ディレクトリ構成
注文のアクション表示をpartial化し、状態ごとにファイルを分割します。
app/views/orders/actions/
_cancelable.html.slim
_shippable.html.slim
_trackable.html.slim
_completed.html.slim
メインビューからの呼び出し
.order-actions
- if order.pending?
= render 'orders/actions/cancelable', order: order
- elsif order.paid?
= render 'orders/actions/shippable', order: order
- elsif order.shipped?
= render 'orders/actions/trackable', order: order
- else
= render 'orders/actions/completed', order: order
partial の例
app/views/orders/actions/_cancelable.html.slim
= link_to cancel_order_path(order), method: :post, class: "btn btn-warning" do
| 注文をキャンセル
app/views/orders/actions/_shippable.html.slim
.btn.btn-secondary.disabled
| 出荷準備中
p.note
| ※ 支払い完了後に出荷手続きを開始します
app/views/orders/actions/_trackable.html.slim
= link_to track_order_path(order), class: "btn btn-info" do
| 発送状況を確認
app/views/orders/actions/_completed.html.slim
= link_to order_receipt_path(order), class: "btn btn-success" do
| 領収書を見る
メリット
- メインビューは
renderのみでシンプル - 各状態ごとの partial に閉じこめるため、編集・把握がしやすい
デメリット
- partial ファイルの数が増えていく
アプローチ2: Helperメソッドにロジック移譲
ヘルパーの実装例
# app/helpers/orders_helper.rb
module OrdersHelper
def order_action_state(order)
if order.pending?
:cancelable
elsif order.paid?
:shippable
elsif order.shipped?
:trackable
else
:completed
end
end
end
ビュー側
.order-actions
- state = order_action_state(order)
- case state
- when :cancelable
= link_to cancel_order_path(order), method: :post, class: "btn btn-warning" do
| 注文をキャンセル
- when :shippable
.btn.btn-secondary.disabled
| 出荷準備中
p.note
| ※ 支払い完了後に出荷手続きを開始します
- when :trackable
= link_to track_order_path(order), class: "btn btn-info" do
| 発送状況を確認
- when :completed
= link_to order_receipt_path(order), class: "btn btn-success" do
| 領収書を見る
メリット
- 状態判定ロジックが一カ所にまとまり、テストもしやすい
- 分岐が増えても、ビューは
case文だけを追えばOK
デメリット
- ビュー内に
case/whenが残るため、完全には平坦化できない
比較と選び方
| 方法 | 可読性 | 拡張性 | 導入コスト |
|---|---|---|---|
| Partial 切り出し | 高 | 中 | 低 |
| Helper 移譲 | 中 | 高 | 中 |
- 簡易な分岐は Partial 切り出しでビューをすっきり
- 複雑な状態判定は Helper 移譲でロジックを集中
まとめと次のステップ
今回紹介した2つの手法を使えば、ビューの深いネストを解消し、可読性・保守性を向上させられます。
要件やチームの開発フローに合わせて最適な手法を選び、ぜひ試してみてください。
さらに ViewComponent や Presenter パターンなど、他のアプローチも検討するとより柔軟な設計が可能です。
Discussion