Rails와 JavaScript 조정을 위한 커스텀 Turbo Stream 액션 활용

Coordinating Rails and JavaScript with Custom Turbo Actions - Unagi

작성자
발행일
2025년 08월 06일

핵심 요약

  • 1 Rails 컨트롤러와 프론트엔드 JavaScript 간의 깔끔한 조정을 위해 커스텀 Turbo Stream 액션을 활용할 수 있습니다.
  • 2 trigger라는 일반적인 Turbo Stream 액션을 통해 서버에서 클라이언트로 특정 DOM 이벤트를 발생시켜 프론트엔드 로직을 분리합니다.
  • 3 이 패턴은 컨트롤러의 비즈니스 로직 집중, 테스트 용이성 증대, 그리고 컴포넌트 간 결합도 감소에 기여합니다.

도입

웹 애플리케이션 개발에서 Rails 컨트롤러와 프론트엔드 JavaScript 간의 효과적인 조율은 복잡성을 증가시키지 않으면서 풍부한 사용자 경험을 제공하는 데 중요합니다. 본 글은 퀴즈 기능의 정답 시 폭죽 애니메이션 구현 사례를 통해, Turbo Stream의 확장성을 활용하여 이러한 조율 문제를 우아하게 해결하는 방법을 제시합니다. 이는 특정 기능 구현을 넘어, 서버와 클라이언트 간의 유연한 통신 메커니즘을 구축하는 데 기여합니다.

커스텀 Turbo Stream 액션의 구현

초기에는 특정 목적(예: 폭죽 애니메이션)을 위한 커스텀 Turbo Stream 액션을 구현했습니다. * 컨트롤러 로직: Rails 컨트롤러는 오직 비즈니스 로직에만 집중하며, 특정 조건(예: 정답)이 충족될 경우 turbo_stream.action(:confetti)를 렌더링합니다. ruby class QuizController < ApplicationController def create if correct_answer? render turbo_stream: turbo_stream.action(:confetti) else # Handle incorrect answer end end end * JavaScript 확장: Turbo.StreamActions 객체에 confetti 함수를 추가하여 해당 액션이 호출될 때 특정 JavaScript 함수(launchConfetti())를 실행하도록 정의합니다. javascript Turbo.StreamActions.confetti = function () { launchConfetti(); };

일반화된 ‘trigger’ 액션으로의 발전

다양한 프론트엔드 기능(스피너 숨기기, 다이얼로그 닫기, 사운드 재생 등)에 대한 조율이 필요해지면서, 개별적인 커스텀 액션 대신 범용적인 trigger 액션의 필요성이 대두되었습니다. * 범용 trigger 액션: 컨트롤러는 turbo_stream.action(:trigger, "이벤트-이름") 형태로 특정 이벤트를 발생시키도록 지시합니다. 여기서 두 번째 인자는 발생시킬 커스텀 이벤트의 이름이 됩니다. ruby class QuizController < ApplicationController def create if correct_answer? render turbo_stream: turbo_stream.action(:trigger, "launch-confetti") else # ... end end end * 이벤트 디스패치: Turbo.StreamActions.trigger 함수는 Turbo Stream 응답을 받아 this.target에 명시된 이름으로 DOM 이벤트를 발생시킵니다. javascript Turbo.StreamActions.trigger = function () { document.dispatchEvent(new Event(this.target)); };

프론트엔드 컴포넌트의 이벤트 리스너 활용

trigger 액션을 통해 발생한 커스텀 DOM 이벤트는 프론트엔드 컴포넌트가 독립적으로 반응할 수 있는 기반을 제공합니다. * Stimulus 컨트롤러: Stimulus 컨트롤러와 같은 프론트엔드 컴포넌트는 document.addEventListener를 사용하여 특정 이벤트를 수신하고, 해당 이벤트 발생 시 정의된 콜백 함수를 실행합니다. ```javascript export default class extends Controller { connect() { document.addEventListener(“launch-confetti”, this.launchConfetti); }

  launchConfetti() {
    // 폭죽 애니메이션 로직
  }
}
``` *   **다양한 활용 사례**: 이 패턴은 다음과 같은 다양한 시나리오에 적용될 수 있습니다.
*   `hide-loading-spinner`: 데이터 로드 성공 후 로딩 스피너 숨기기
*   `play-notification-sound`: 중요한 알림에 대한 사운드 재생
*   `update-progress-bar`: 장시간 실행되는 프로세스 중 진행률 바 업데이트
*   `trigger-analytics-event`: 사용자 행동 추적을 위한 분석 이벤트 발생

결론

이 접근 방식은 Rails 컨트롤러가 데이터 및 비즈니스 로직에만 집중하도록 유지하면서도 풍부한 프론트엔드 상호작용을 가능하게 합니다. 이벤트 기반의 분리된 구조는 테스트를 용이하게 하고, 여러 컴포넌트가 서로에게 결합되지 않고도 조율될 수 있도록 합니다. 커스텀 Turbo Stream 액션의 활용은 새로운 의존성을 추가하기보다 기존 도구를 확장하는 것이 더 효율적일 수 있음을 보여주며, 실제 사용 사례에서 최적의 추상화가 어떻게 도출될 수 있는지를 잘 나타냅니다.

댓글 0

댓글 작성

0/1000
정중하고 건설적인 댓글을 작성해 주세요.

아직 댓글이 없습니다

첫 번째 댓글을 작성해보세요!