Lesson CRUD — Admin 컨트롤러 (Curriculum 하위) + 뷰 + content_type 렌더링 + 테스트
ID: c03da9ae-5e7c-4216-b640-97bf35a305c8
## 목표
Admin 네임스페이스에서 Lesson CRUD 구현. Curriculum 하위 리소스. content_type별 렌더링. Markdown 지원.
## 현재 상태
- Lesson 모델: belongs_to :curriculum, has_many :user_lesson_progresses. title, content, content_type(default: "article"), video_url, read_time_minutes, position, published, required_role(default: 0). scope :published
- Admin::LessonsController 스텁 존재 (빈 액션 7개)
- Admin::BaseController 존재 (require_admin)
- 라우트: `namespace :admin { resources :curricula do resources :lessons end }`
- Admin::CurriculaController 이미 구현됨 (show 페이지에서 레슨 목록 표시)
- 공용 Partial: _button, _card, _input
## 구현 사항
### 1. Admin::LessonsController
```ruby
class Admin::LessonsController < Admin::BaseController
before_action :set_curriculum
before_action :set_lesson, only: [:show, :edit, :update, :destroy]
def index
@lessons = @curriculum.lessons.order(:position)
end
def show; end
def new
@lesson = @curriculum.lessons.build
end
def create
@lesson = @curriculum.lessons.build(lesson_params)
if @lesson.save
redirect_to admin_curriculum_lesson_path(@curriculum, @lesson), notice: "레슨이 생성되었습니다."
else
render :new, status: :unprocessable_entity
end
end
def edit; end
def update
if @lesson.update(lesson_params)
redirect_to admin_curriculum_lesson_path(@curriculum, @lesson), notice: "레슨이 수정되었습니다."
else
render :edit, status: :unprocessable_entity
end
end
def destroy
@lesson.destroy
redirect_to admin_curriculum_lessons_path(@curriculum), notice: "레슨이 삭제되었습니다."
end
private
def set_curriculum
@curriculum = Curriculum.find(params[:curriculum_id])
end
def set_lesson
@lesson = @curriculum.lessons.find(params[:id])
end
def lesson_params
params.require(:lesson).permit(:title, :content, :content_type, :video_url, :read_time_minutes, :position, :published, :required_role)
end
end
```
### 2. 뷰 (app/views/admin/lessons/)
- 다크 테마 (bg-bg, text-text-primary, bg-surface)
- 기존 Partial 활용
- index: 레슨 테이블 (position 순서), content_type 아이콘, published 상태
- show: 레슨 상세 — content_type에 따라:
- article: Markdown 렌더링 (simple_format 또는 sanitize 사용)
- video: video_url 임베드
- guide: Markdown 렌더링
- new/edit: 폼 (_form partial)
- _form: title, content(textarea), content_type(select: article/video/guide), video_url(video 선택 시), read_time_minutes, position, published(체크박스), required_role(select: 0=free/1=cohort/2=admin)
### 3. Markdown 렌더링
- 간단하게 `simple_format` 또는 content를 그대로 표시 (redcarpet gem이 없으면 simple_format 사용)
- Admin show 페이지에서 미리보기
### 4. content_type별 처리
- article: content(Markdown) 표시
- video: video_url iframe 임베드 (YouTube/Vimeo 지원)
- guide: content 표시 + 가이드 스타일
### ⚠️ 주의
- admin/lessons/ 범위만 수정
- developer-2가 동시에 서비스 객체 작업 중 — 모델 수정 불필요
- required_role은 integer (0=free, 1=cohort, 2=admin) — PRD에서 pro가 있었지만 v2.1에서 제거됨. free/cohort/admin만 사용
- User 모델 건드리지 않기
- 한국어 Flash 메시지
### 테스트 (TDD)
- Admin::LessonsController 테스트:
- admin만 접근 가능
- CRUD 전체 (curriculum 하위 리소스)
- content_type별 생성
- 유효하지 않은 입력 시 에러
- fixture: lessons.yml 확인 후 사용
### 완료 기준
- Admin 레슨 CRUD 동작 (Curriculum 하위)
- content_type별 렌더링
- position 정렬
- 컨트롤러 테스트 통과
- bin/rails test 전체 통과
첨부 이미지
이미지 추가 (Ctrl+V로 붙여넣기 또는 클릭)
JPEG, PNG, GIF, WebP / 최대 10MB
활동 로그
-
Ddeveloper-1 상태 변경: 할 일 → 리뷰
2026년 03월 26일 08:51:11