0
0

リファクタリング: ScheduleServiceを導入する(パート2)

Last updated at Posted at 2024-05-04

前回の記事

ScheduleService の実装詳細

前回の記事で概要を説明した後、このパートでは ScheduleService の具体的なメソッド実装と、コントローラーでの利用方法を深掘りします。

1. ScheduleServiceのメソッド実装

ScheduleService クラスの中核となるメソッドは、特定の日に提供可能なスタッフのスケジュールを取得し、それを元に利用可能な時間スロットの状況を分析します。

build_staff_schedule_map メソッド

このメソッドは、指定されたサービスを提供可能なスタッフのスケジュールをマッピングします。スタッフごとにその日のスケジュールを配列として保存します。

  def self.build_staff_schedule_map(working_staffs, service, date)
    working_staffs.each_with_object({}) do |staff, map|
      if staff.services.include?(service)
        map[staff.id] = staff.schedules.select { |sch| sch.date == date }
      end
    end
  end

analyze_time_slots メソッド

各時間スロットに対して、提供可能なスタッフ数を計算し、それに基づいて時間スロットの状態を評価します。ここではシンプルに、スタッフが1人のみ利用可能な場合は△、複数いる場合は○、いない場合は×としています。

  def self.generate_time_slots_availability(staff_schedule_map, time_slots)
    time_slots.each_with_object({}) do |slot, inner_hash|
      available_staff_count = staff_schedule_map.count do |_, schedules|
        schedules.any? do |schedule|
          start_time = schedule.start_time.strftime("%H:%M")
          end_time = schedule.end_time.strftime("%H:%M")
          time_in_slot = start_time <= slot && slot < end_time
          time_unavailable = schedule.time_tables.any? { |tt| !tt.available && tt.start_time.strftime("%H:%M") <= slot && tt.end_time.strftime("%H:%M") > slot }
          time_in_slot && !time_unavailable
        end
      end
      inner_hash[slot] = case available_staff_count
                         when 0 then '×'
                         when 1 then '△'
                         else '○'
                         end
    end
  end

2. コントローラでのScheduleServiceの利用

ReservationsControllerSchedulesControllerScheduleService を利用する例を示します。このサービスを利用することで、コントローラはビジネスロジックから解放され、主にデータの受け渡しと応答の管理に集中できます。

# ReservationsController
def confirm
  @company = Company.find(params[:company_id])
  @date = params[:date] || Date.today
  @services = @company.services
  @time_slots = generate_time_slots(@company)
  @service_availability = ScheduleService.calculate_availability(@company, @date, @services, @time_slots)
end

# SchedulesController
def index
  @company = Company.find(params[:company_id])
  @date = params[:date] || Date.today
  @services = @company.services
  @time_slots = generate_time_slots(@company)
  @service_availability = ScheduleService.calculate_availability(@company, @date, @services, @time_slots)
end

まとめ

ScheduleService の導入により、アプリケーションのコードベースはより整理され、各コンポーネントの責任が明確になりました。サービスオブジェクトの導入は、特に大規模なアプリケーションや複数のコンポーネント間で共有される複雑なビジネスロジックを持つ場合に有効です。これにより、アプリケーションの拡張性と保守性が向上し、将来の開発が容易になります。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0