클라이언트의 CMS는 다양한 규칙을 가진 여러 자회사를 관리해야 했으며, 사용자들은 회사 간 데이터를 쉽게 볼 수 있고 전환할 수 있어야 했습니다. 데이터는 외래 테이블에 company_id
컬럼과 함께 존재했지만, 레거시 시스템의 제약으로 테이블 변경은 어려웠습니다. 회사 간 강력한 보안 분리가 불필요했기에, 별도 스키마나 데이터베이스 분리 대신 모든 외래 테이블을 퍼블릭 스키마에 두기로 결정했습니다. 핵심 과제는 요청별로 현재 회사를 식별하고 그에 따라 데이터를 필터링하는 것이었고, Rails의 ActiveSupport::CurrentAttributes
가 이러한 전역적인, 요청별 속성 관리에 적합하다고 판단되었습니다.
구현은 ActiveSupport::CurrentAttributes
를 상속받는 Current
클래스에 company_id
속성을 정의하는 것으로 시작했습니다. 다음으로, ApplicationRecord
를 상속하는 MultitenantRecord
클래스에 default_scope
를 추가하여 Current.company_id
에 따라 레코드를 자동으로 필터링하도록 했습니다. 이때 company_id
가 설정되지 않으면 오류를 발생시키는 가드 절을 포함했습니다. 마지막으로, ApplicationController
의 before_action
에서 인증된 사용자의 company_id
를 Current.company_id
에 할당하여 각 요청에 대한 현재 회사를 지정했습니다. 이로써 대부분의 멀티테넌시 기능이 구현되었고, Current
객체는 뷰의 기능 플래그나 외부 API 연동 등 다양한 곳에서 활용되었습니다.
그러나 두 가지 주요 난관이 있었습니다. 첫째, 백그라운드 작업은 별도의 프로세스에서 실행되므로 CurrentAttributes
값이 자동으로 전달되지 않아 company_id
를 각 작업에 명시적으로 전달해야 했습니다. 둘째, 요청 스펙(request specs)에서 컨트롤러 처리 후 CurrentAttributes
값이 초기화되어 테스트 실패가 발생했습니다. 이 문제는 Current
클래스에 with_company
헬퍼 메서드를 추가하여 set
블록 내에서 company_id
컨텍스트를 유지하도록 함으로써 해결했습니다.