Railsアプリの複雑な条件文を撃退するViewModel

こんにちは!私、キラメックスのブートキャンプ事業部で開発をしております鈴木です! 社内では、Railsで新規機能の開発、保守を主にやっていたり、Railsのバージョンアップなども担当しております!

今回は、複雑な条件文を撃退するViewModelを紹介します!

TechAcademyを支えるアプリケーションの特徴

TechAcademyのアプリケーションは下記の特徴があります。

  • 非SPAのため、レンダリングは全てサーバー側でRailsが担当(Slimで記述)
  • サービスとしてToC向けのTechAcademy、ToB向けの研修用のTechAcademy、転職のTechAcacademyキャリアが1つのレポジトリで管理されているモノリシックなアプリケーション
  • ロールが6つほど管理されている
  • ToC向けに25コース以上を提供している

TechAcademyの受講システムのホーム画面

TechAcademyの例でいうと、受講システムのホーム画面が特に表示条件が複雑化しています。 具体的にいうと、ToC向けのTechAcademy、ToB向けの研修用のTechAcademyで同じテンプレートを使用しており、各サービスごとで表示するコンテンツが異なるため、表示条件が複雑になっています。 また、Railsレンダリングされている以上、表示条件をmodel内に実装してしまうケースがふえ、Fat Modelになる傾向になります。 SPAにして、Vueなどのコンポーネント単位でテストが行えれば良いのですが、Slimを採用しているため、 各コンポーネントごとでのテストが行いにくい状態になっています。

ここでViewModelを採用しました

実際のコードは以下です。

  • コントローラ(app/controllers/learnings/dashboard_controller.rb)
Class Learnings::DashboardController < ApplicationController
  def index
    @progress_view_model = Dashboards::ProgressViewModel.new(course)
  end
end
  • ビューモデル(app/view_models/learnings/dashboard_view_model.rb)
Class Dashboards::ProgressViewModel
  def initialize(course)
    @course = course
  end

  # 研修の場合
  def is_training?
  end

  # ToCの場合
  def is_to_c?
  end

  # デザイン系のコースの場合
  def is_design?
    course.is_design?
  end

  private
  attr_reader :course
end
  • テンプレート(app/views/learnings/dashboards/index.html.slim)
  = render partial: 'progress', locals: { progress_view_model: @progress_view_model }

app/views/learnings/dashboards/_progress.html.slim

- if progress_dash_board.is_training?

- if progress_dash_board.is_to_c?

- if progress_dash_board.is_design?

ポイントとしては、ViewModelの命名はコントローラ + コンポーネント名にすることですかね。

メリットとデメリット

メリットは下記ですね!

  • POROのViewModelに全ての条件を閉じ込めることによって、テストが書きやすくなります。
  • コンポーネント単位でViewModelを定義することにより、ソースが追いやすい。
  • インスタンス変数もViewModelに閉じ込めることができ、管理が煩雑にならない
  • 変化が激しいView周りでPOROを採用することにより、Controller内を編集するよりもViewModelを捨てるだけでよいため、変更に追従しやすい

またデメリットはこちら!

  • 他のコンポーネントでも同様の条件文があった際に、DRYに書けない可能性がある
  • インスタンス変数が各コンポーネントごとに定義すると、無駄なクエリを発行してしまう可能性がある(クエリキャッシュがあれば、特に意識しなくても良いですが)

いかがでしたでしょうか? SPAに移行するには、フロントエンドの学習コストと採用コストがかさむので、まずはミニマムで試したい方は是非!

twitter.com

一緒に教育サービスを提供していきたい方がいれば、是非こちらから!

www.wantedly.com