Rails 7의 출시가 코앞으로 다가왔습니다. 확정된 출시일은 아직 발표되지 않았지만, 크리스마스 전에는 만나볼 수 있을 것으로 예상되므로 그리 멀지 않았습니다. 이 글을 작성하는 시점의 최신 버전은 첫 번째 릴리스 후보(release candidate)인 7.0.0.rc1입니다. Basecamp, HEY, GitHub, Shopify 등 주요 서비스들이 이미 프로덕션 환경에서 Rails 7 알파 버전을 운영해 왔기 때문에, 릴리스 후보 단계에서도 상당히 안정적인 품질을 기대할 수 있습니다.
이번 글에서는 Rails 7이 가져올 주요 신규 기능과 변경 사항을 살펴보겠습니다.
Node.js와 Webpack 없이도 JavaScript 개발 가능
놀라시겠지만 사실입니다! Rails 7에서는 JavaScript 개발에 NodeJS나 Webpack이 더 이상 필수가 아닙니다. 물론 npm 패키지는 여전히 사용할 수 있습니다.
Babel로 ES6 코드를 트랜스파일하고 Webpack으로 번들링하는 과정은 상당한 설정 작업을 요구합니다. Rails는 Webpacker 젬을 통해 이를 잘 지원해 왔지만, 그만큼 많은 복잡성이 따랐고, 특히 업그레이드 호환성을 유지하면서 구조를 이해하거나 수정하기가 쉽지 않았습니다.
이제 rails new로 생성하는 새 앱의 기본 설정은 importmaps-rails 젬을 활용한 import map 방식입니다. package.json을 작성하고 npm이나 yarn으로 의존성을 설치하는 대신, ./bin/importmap CLI로 의존성을 고정(pin)하거나 해제(unpin)하거나 업데이트하면 됩니다.
예를 들어 date-fns를 설치하려면 다음과 같이 실행합니다:
그러면 config/importmap.rb에 다음과 같은 한 줄이 추가됩니다:
JavaScript 코드에서는 기존과 동일하게 사용하면 됩니다:
이 설정에서 한 가지 유의할 점은, 작성한 코드와 브라우저가 받는 코드 사이에 트랜스파일 과정이 없다는 것입니다. 다행히 현재 주요 브라우저들은 대부분 ES6를 기본 지원하므로 대체로 문제가 되지 않습니다.
하지만 TypeScript나 JSX처럼 사용 전에 JS로 트랜스파일이 필요한 기술은 사용할 수 없습니다. 따라서 JSX를 활용한 React를 사용하려면 여전히 다른 빌드 도구(webpack/rollup/esbuild) 기반의 구성으로 전환해야 합니다.
Rails 7은 이 과정도 대신 처리해 줍니다. 원하는 전략을 골라 명령어 하나만 실행하면 됩니다:
Turbolinks와 UJS는 Turbo와 Stimulus로 교체
Rails 7로 생성된 애플리케이션은 Turbolinks와 UJS 대신 Hotwire의 Turbo와 Stimulus를 기본적으로 사용합니다. Hotwire는 HTML을 네트워크를 통해 전송함으로써 DOM을 빠르게 갱신하는 새로운 접근 방식입니다.
데이터베이스 레이어 암호화
Rails 7에서는 ActiveRecord::Base의 encrypts 메서드를 사용해 특정 데이터베이스 필드를 암호화 대상으로 지정할 수 있습니다. 초기 설정만 마치면 다음과 같은 코드를 작성할 수 있습니다:
암호화된 속성도 일반 속성과 동일하게 사용할 수 있으며, Rails 7이 데이터베이스와 애플리케이션 사이에서 자동으로 암호화와 복호화를 처리합니다.
다만 한 가지 주의할 점이 있습니다. encrypts 메서드에 deterministic: true 옵션을 지정하지 않으면 해당 필드로 데이터베이스를 조회할 수 없습니다. 결정론적(deterministic) 모드는 기본 비결정론적 모드보다 보안성이 낮으므로, 반드시 조회가 필요한 속성에만 사용하는 것이 좋습니다.
비동기 쿼리
새롭게 추가된 load_async 메서드를 사용하면 데이터 조회 시 결과를 백그라운드에서 미리 가져올 수 있습니다. 하나의 컨트롤러 액션에서 서로 연관 없는 여러 쿼리를 실행해야 할 때 특히 유용합니다:
두 쿼리가 동시에 백그라운드에서 실행됩니다. 각 쿼리가 200ms씩 걸린다면, 순차 실행 시 400ms가 소요되는 반면 이 방식에서는 약 200ms로 단축됩니다.
Rails 7의 Zeitwerk 모드
아직 클래식 로더(classic loader)를 사용하는 기존 애플리케이션에게는 주요 변경 사항입니다. 모든 Rails 7 애플리케이션은 Zeitwerk 모드를 사용해야 하지만, 전환 자체는 비교적 간단합니다. 자세한 내용은 Zeitwerk 업그레이드 가이드를 참고하세요.
그 외 Rails 7 업데이트
작업 무제한 재시도
ActiveJob에서 이제 retry_on의 attempts 매개변수로 :unlimited를 전달할 수 있습니다. 최대 시도 횟수 제한 없이 작업을 계속 재시도합니다.
명명된 변형(Named Variants)
ActiveStorage에서 이제 변형(variant)에 이름을 붙일 수 있어, 접근할 때마다 크기를 지정하지 않아도 됩니다.
해시를 HTML 속성으로 변환
뷰에서 해시를 HTML 속성으로 변환해 주는 새로운 tag.attributes 메서드가 추가되었습니다:
위 코드는 아래와 같이 출력됩니다:
Ruby debug 젬
디버깅 기본 도구가 byebug에서 debug 젬으로 변경되었습니다. 더 이상 byebug를 호출하는 대신, 코드에서 debugger를 호출해 디버깅 세션에 진입합니다.
sole로 단일 레코드 검증
레코드를 조회할 때 쿼리가 정확히 하나의 레코드만 반환해야 한다고 보장하고 싶다면, first나 find_by 대신 sole 또는 find_sole_by를 호출할 수 있습니다.
연관 관계 존재 여부 확인
이제 조인 후 ID 존재 여부를 확인하는 대신, where.associated(:association)으로 레코드에 연관 관계가 있는지 간편하게 확인할 수 있습니다.
컨트롤러 액션에서 생성 중인 파일 스트리밍
컨트롤러 액션 내에서 send_stream을 사용하면 실시간으로 생성 중인 파일을 즉시 스트리밍할 수 있습니다.
사용자에게 즉각적인(부분) 응답을 제공하여 진행 상황을 인지시킬 수 있으며, Heroku에 배포하는 경우 추가적인 이점도 있습니다.
파일 스트리밍이 즉시 시작되기 때문에 Heroku가 연결을 종료하지 않습니다. 덕분에 30초 이상 걸리는 일회성 파일 생성 작업에 굳이 백그라운드 잡을 활용할 필요가 없습니다.
Rails 7로 업그레이드하기
이전 버전들과 마찬가지로 업그레이드 절차는 간단합니다. 아직 공식 업그레이드 가이드는 나오지 않았지만, 단계는 동일합니다:
- Gemfile에서 Rails 버전 번호를 변경하고(발행일 기준
7.0.0.rc1)bundle update를 실행합니다. bundle exec rails app:update를 실행합니다. 대화형 CLI의 안내에 따라 필요한 파일을 추가/교체/수정합니다.- 테스트를 실행하여 모든 것이 예상대로 동작하는지 확인합니다.
마무리
버그 수정, 기능, 변경 사항의 전체 목록은 Rails 7 릴리스 노트에서 확인할 수 있습니다. 아직 완전하지는 않지만 곧 업데이트될 것으로 예상됩니다.
여전히 Rails 6 이하 버전을 사용 중이라면 주의하세요. Rails 7 정식 출시와 함께 Rails 6.1은 "보안 문제만 수정" 모드로 전환되어 더 이상 버그 수정을 받지 못합니다. 또한 Rails 5.2는 어떤 수정도 받지 못하게 되며, 이는 곧 EOL(서비스 종료)을 의미합니다.
즐거운 코딩 되세요!
P.S. Ruby Magic 포스트가 발행되는 즉시 읽고 싶다면 Ruby Magic 뉴스레터를 구독하고 어떤 글도 놓치지 마세요!
Pulkit Goyal
게스트 저자 Pulkit는 시니어 풀스택 엔지니어이자 컨설턴트입니다. 여가 시간에는 자신의 경험을 블로그에 기록합니다.
Pulkit Goyal의 모든 글 보기