Rails 커뮤니티 게시판에 마크다운 에디터 + 좋아요 시스템 붙이기 — importmap 환경에서의 현실적인 선택

커뮤니티 게시판에 Q&A 기능을 만들고 있었다. 질문을 올릴 때 코드 블록이나 볼드 처리를 할 수 있어야 했고, 추천순 정렬 필터도 있으니 좋아요 기능도 필요했다. 그런데 이 프로젝트는 importmap-rails 기반이라 npm 패키지를 자유롭게 쓸 수 없는 환경이었다. 결론부터 말하면, 외부 라이브러리 없이 기존 Stimulus 컨트롤러를 재사용하는 게 가장 좋은 선택이었다. 그 과정에서 겪은 삽질들을 정리한다. importmap-rails 환경에서 마크다운 에디터 선택지 Rails 8의 기본 JS 관리 방식은 importmap이다. esbuild나 webpack 같은 번들러 없이, ESM(ES Modules)을 CDN에서 직접 가져다 쓴다. 설정이 단순한 대신 CommonJS 전용 패키지나 CSS를 함께 번들링해야 하는 라이브러리는 쓰기 어렵다. ...

2026-03-24 · 9분 소요 · Seunghan

Hotwire Native + Rails 8 삽질 7가지 — 실기기에서만 터지는 버그들

Rails 8 + Hotwire Native으로 만든 모바일 앱의 대시보드 페이지를 Render에 배포한 뒤 실기기에서 점검하면서 만난 삽질 7가지를 정리했다. WKWebView 위에서 돌아가는 하이브리드 앱 특성상, 데스크톱 브라우저에서는 발견되지 않는 함정들이 많았다. 이 글에서 다루는 주요 키워드: Hotwire Native 모바일 레이아웃, Content Security Policy CDN 차단, Turbo const/let 재선언 에러, backdrop-filter 성능, Stimulus 컨트롤러 자동 등록, CSS contain 최적화. 프로젝트 환경 Backend: Rails 8 + PostgreSQL Frontend: Hotwire (Turbo + Stimulus) + ERB + Tailwind CSS 4 Mobile: Hotwire Native (iOS WKWebView) Realtime: ActionCable (WebSocket) Deploy: Render.com Asset Pipeline: importmap-rails (CDN pin 방식) 대시보드 페이지 구성: 코트 카드 grid (코트 수 x 라운드 수), 선수 DnD 리스트, 경기 목록, 교류 현황 통계. 코트 5개 x 8라운드 = 40장의 카드가 한 페이지에 렌더링되는 구조. ...

2026-03-21 · 8분 소요 · Seunghan

Rails 8 Hotwire 실전 삽질기 — DnD 배정, N+1 자동 감지, 테마별 Favicon

Rails 8 + Hotwire로 실시간 토너먼트 대시보드를 만들면서 하루 동안 겪은 3가지 삽질과 해결 과정. 이 문제들은 엣지 케이스가 아니라, Hotwire 프로그래밍 모델이 런타임에서 드러내는 자연스러운 마찰 지점들이다. 1. Turbo Stream + Stimulus DnD: DOM 교체 후 이벤트가 사라진다 문제 선수 칩을 코트 카드에 드래그하면 서버에 POST → Turbo Stream으로 코트 카드와 선수 목록을 교체하는 구조를 만들었다. 첫 번째 드래그는 잘 된다. 두 번째부터 아무 반응이 없다. 이벤트도, 요청도, 응답도 없다. ...

2026-03-21 · 9분 소요 · Seunghan

fetch() + PATCH + 302 Redirect = 보이지 않는 버그

Stimulus 컨트롤러에서 badge 선택 UI를 만들었다. 옵션을 클릭하면 fetch()로 PATCH를 보내고, 서버가 업데이트한 뒤 성공/실패를 표시하는 단순한 구조다. 그런데 DB는 업데이트되는데 UI가 실패 표시를 하면서 원래 값으로 되돌아갔다. 서버 로그를 열기 전까지는 원인을 전혀 짐작할 수 없었다. 증상 badge를 클릭하면: 잠깐 선택 스타일이 바뀜 곧바로 원래 값으로 revert 에러 인디케이터(X) 표시 다른 필드(모드, 대진표 유형)는 정상 동작하는데, 특정 필드만 실패했다. 모델 validation 문제도 아니고, 권한 문제도 아니었다. 서버 로그에서 본 진짜 원인 Started PATCH "/resources/54" for ::1 Processing by ResourcesController#update as TURBO_STREAM Parameters: {"resource"=>{"field_name"=>"new_value"}, "id"=>"54"} ... UPDATE "resources" SET "field_name" = 1 WHERE "id" = 54 COMMIT Redirected to http://localhost:3000/resources/54/dashboard Completed 302 Found in 22ms Started PATCH "/resources/54/dashboard" for ::1 ActionController::RoutingError (No route matches [PATCH] "/resources/54/dashboard"): DB 업데이트는 성공했다. 그런데 서버가 redirect_to dashboard로 302를 보냈고, fetch가 그 redirect를 따라가면서 PATCH method를 유지한 채 dashboard URL로 요청을 보냈다. Dashboard는 GET만 받으므로 RoutingError가 터졌다. ...

2026-03-20 · 5분 소요 · Seunghan
Rails Turbo Stream Bracket BYE Slot Debugging

Turbo Stream 누락 + BYE 슬롯 재활용 안 되는 버그 — Rails 8 대진표 디버깅 기록

대진표 관리 앱에서 두 가지 버그가 동시에 나왔다. 선수 추가 폼이 작동하지 않는 것처럼 보임 — 추가 버튼을 눌러도 목록이 갱신 안 됨 자동배정 후 선수를 추가하고 다시 자동배정해도 빈 슬롯이 안 채워짐 겉으로 보면 “선수 생성이 안 된다"인데, 실제로는 두 개의 독립적인 버그가 동시에 나타난 케이스였다. 증상 정리 조작 기대 실제 선수 추가 폼 제출 목록에 즉시 반영 아무 변화 없음 (새로고침하면 있음) 자동배정 → 선수 추가 → 자동배정 새 선수가 빈 슬롯에 배정 “배정할 선수가 없습니다” or 변화 없음 빈 슬롯 표시 공란 “BYE” 텍스트 노출 버그 1: Turbo Stream 응답 누락 원인 Rails 8 + Turbo 환경에서 form_with는 기본적으로 turbo_stream 포맷으로 제출한다. 컨트롤러의 create 액션이 이렇게 되어 있었다: ...

2026-03-19 · 4분 소요 · Seunghan

Rails 8 + Hotwire Native iOS — 실시간 알림 뱃지 & 사이드 메뉴 네비게이션 구현

Rails 8 기반 Hotwire Native iOS 앱에서 두 가지 문제를 해결한 기록이다. 알림 뱃지 실시간 갱신 — 서버에서 알림이 생성되는 순간 앱 아이콘 뱃지와 내비게이션 벨 버튼을 즉시 업데이트 사이드 메뉴 네비게이션 누락 — tournament ID 같은 동적 파라미터가 필요한 URL을 사이드 메뉴에서 올바르게 이동 1. 문제 배경 알림 뱃지 APNs 푸시 알림의 badge 필드를 설정하지 않으면 iOS 앱 아이콘에 숫자가 표시되지 않는다. 또한 알림을 읽어도 뱃지가 초기화되지 않는 문제가 있었다. ...

2026-03-17 · 7분 소요 · Seunghan

Rails 8 + Hotwire Native 앱의 역할 기반 UI 분리와 모바일 최적화 삽질기

Rails 8 + Hotwire Native 조합으로 iOS 앱을 운영하는 중에, 하루 동안 발생한 여러 문제를 연쇄적으로 해결한 기록이다. 작은 UI 깨짐에서 시작해서 권한 체계 재설계까지 이어진 과정을 정리한다. Hotwire Native의 핵심 매력은 하나의 Rails 앱으로 웹과 네이티브 iOS/Android를 동시에 지원한다는 점이다. 하지만 이 구조는 “웹에서 잘 보이면 앱에서도 잘 보인다"는 착각을 쉽게 심어준다. 실제로는 WKWebView의 렌더링 환경, 네이티브 네비게이션 바의 존재, 역할별 UI 분기 등 웹 브라우저와 전혀 다른 고려사항이 따라온다. ...

2026-03-17 · 7분 소요 · Seunghan
Stimulus DnD Collapse Dashboard

Rails 대시보드에 DnD 카드 순서 변경 + 접기 구현 — SortableJS + Stimulus + CSS 트릭

스포츠 대회 관리 앱의 대시보드에 두 가지 기능을 추가하는 작업이었다. 카드 순서 DnD 변경 — 내 경기 / 대진표 / 경기 목록 카드를 원하는 순서로 재배치 카드 접기/펼치기 — 관심 없는 섹션을 접어 화면을 간결하게 각각은 단순해 보이지만, Turbo Frame lazy loading과 함께 동작해야 하고, 새로고침 후에도 상태가 유지되어야 한다는 조건이 붙으면 신경 쓸 게 늘어난다. 1. DnD 라이브러리 선택 처음에는 native HTML5 Drag & Drop API로 직접 구현했다. dragstart, dragover, drop 이벤트를 다 붙이고 DOM 조작으로 순서를 바꾸는 방식인데, 실제로 동작하게 만드는 건 어렵지 않다. ...

2026-03-17 · 5분 소요 · Seunghan
Tailwind v4 CSS Variable Theme System

Tailwind v4 CSS 변수 오버라이드로 앱 전체 테마 교체하기

테마 시스템을 구현할 때 흔히 생각하는 방법은 컴포넌트마다 조건부 클래스를 추가하는 것이다. 하지만 기존 코드를 건드리지 않고 CSS 변수 한 블록만으로 앱 전체 색상을 바꿀 수 있다면? Tailwind v4에서는 그게 가능하다. Tailwind v4의 CSS 변수 컴파일 방식 이 패턴 전체를 가능하게 만드는 아키텍처 변화는 미묘하지만 근본적이다. Tailwind v4는 유틸리티 클래스를 하드코딩된 값이 아니라 CSS 변수 참조로 컴파일한다. /* Tailwind v4가 생성하는 CSS */ .bg-emerald-700 { background-color: var(--color-emerald-700); } .text-emerald-600 { color: var(--color-emerald-600); } .border-emerald-500 { border-color: var(--color-emerald-500); } Tailwind v3에서는 bg-emerald-700이 background-color: #047857로 컴파일됐다. 스타일시트에 hex 값이 직접 박혔다. v4에서는 background-color: var(--color-emerald-700)으로 컴파일된다. 실제 색상 값은 :root에 선언된 CSS 커스텀 프로퍼티에 저장된다. ...

2026-03-17 · 7분 소요 · Seunghan
Bracket FAB Audit Log Rails

대진표에 FAB 피드백 버튼, 수정 권한 체계, Audit Log 붙이기 — Rails 8 삽질 기록

한 번에 세 가지 기능을 동시에 설계하다 보면 서로 얽히는 부분이 생긴다. 이번에는 대진표 관리 앱에 다음을 추가했다. FAB 피드백 버튼 — 우측 하단 플로팅 버튼 → Telegram 전송 역할 기반 대진표 수정 권한 — 대회 vs 친선 모드에 따라 일반 참가자에게 수정 권한 부여 여부 선택 Audit Log — 누가 언제 무엇을 바꿨는지 전/후 데이터와 함께 기록 각각은 단순해 보이지만, 셋을 한꺼번에 설계하다 보니 “어디서 권한을 체크하고, 어디서 로그를 남기고, 어디까지 UI에 노출하는가"에 대한 결정이 계속 붙었다. ...

2026-03-17 · 5분 소요 · Seunghan
개인정보처리방침 이용약관 면책조항 문의