초기 문제 상황은 Teacher
모델에 available_places
와 같은 비즈니스 로직 외에 뷰에서 필요한 colour_coded_availability
와 같은 CSS 클래스 생성 로직이 포함되는 것이었습니다. 모델은 순수한 비즈니스 로직을 담당해야 하므로, 이러한 뷰 로직은 분리되어야 합니다. 이를 위해 TeacherDecorator
라는 데코레이터 클래스를 생성하여 Teacher
인스턴스를 래핑하고 colour_coded_availability
메서드를 정의했습니다.
하지만 데코레이터를 적용한 후 teachers/index.html.erb
뷰에서 래핑된 teacher
객체의 full_name
과 같은 모델 본연의 메서드를 호출할 때 NoMethodError
가 발생했습니다. 이는 데코레이터가 래핑된 객체의 메서드를 알지 못하기 때문입니다. 이 문제를 해결하기 위해 Ruby의 핵심 기능인 method_missing
과 respond_to_missing?
을 활용했습니다. method_missing
을 오버라이드하여 데코레이터에 정의되지 않은 메서드 호출이 발생하면 래핑된 teacher
객체로 해당 호출을 public_send
를 통해 위임하도록 구현했습니다. respond_to_missing?
또한 래핑된 객체의 메서드 응답 여부를 확인하도록 하여, NoMethodError
없이 메서드 호출이 가능해졌습니다.
이러한 위임 로직을 다른 데코레이터에서도 재사용하기 위해 ApplicationDecorator
라는 상위 클래스를 생성하고, TeacherDecorator
가 이를 상속하도록 하여 공통 위임 로직을 추상화했습니다. 이로써 각 데코레이터는 자신만의 뷰 로직에만 집중할 수 있게 되었습니다.
더 나아가, Rails의 기본 헬퍼 메서드(edit_teacher_path
등)가 데코레이터 인스턴스를 올바르게 처리하지 못하는 문제가 발생했습니다. 이는 헬퍼가 객체의 to_param
메서드를 호출하여 ID를 얻기 때문인데, 데코레이터가 이를 위임하지 않아 데코레이터 객체 자체가 경로에 포함되는 문제가 발생했습니다. 이 문제를 해결하기 위해 ApplicationDecorator
에 delegate :to_param, to: :record
를 추가하여 to_param
메서드 호출 또한 래핑된 객체로 위임하도록 했습니다.
그러나 모든 Rails 기본 동작을 수동으로 위임하는 것은 복잡성을 증가시킬 수 있습니다. 이에 대한 궁극적인 해결책으로 Ruby 표준 라이브러리의 SimpleDelegator
를 도입했습니다. SimpleDelegator
는 생성자에 전달된 객체의 모든 지원되는 메서드 호출을 자동으로 위임하는 기능을 제공합니다. 이를 통해 ApplicationDecorator
에서 initialize
, method_missing
, respond_to_missing?
, to_param
등의 복잡한 위임 로직을 완전히 제거하고, 단지 ApplicationDecorator < SimpleDelegator
로 상속받는 것만으로 모든 위임이 자동으로 처리되도록 구현했습니다. SimpleDelegator
는 래핑된 객체에 __getobj__
메서드를 통해 접근할 수 있도록 제공하며, 이를 alias_method
로 teacher
와 같이 의미 있는 이름으로 변경하여 데코레이터 내부에서 사용의 편의성을 높였습니다. 이로써 데코레이터 코드는 놀랍도록 간결해졌고, 원하는 뷰 로직만 포함하게 되었습니다.