rubyonrails.org에서 더 보기:

이 파일을 GITHUB에서 읽지 마세요. 가이드는 https://guides.rubyonrails.org 에 게시되어 있습니다.

Ruby on Rails 업그레이드하기

이 가이드는 애플리케이션을 최신 버전의 Ruby on Rails로 업그레이드할 때 따라야 할 단계들을 제공합니다. 이러한 단계들은 개별 릴리스 가이드에서도 확인할 수 있습니다.

1 일반적인 조언

기존 애플리케이션을 업그레이드하기 전에, 업그레이드할 만한 좋은 이유가 있는지 확인해야 합니다. 새로운 기능의 필요성, 오래된 코드에 대한 지원을 찾기가 점점 어려워지는 점, 그리고 사용 가능한 시간과 기술 등 여러 요소들의 균형을 맞춰야 합니다.

1.1 Test Coverage

애플리케이션이 업그레이드 후에도 여전히 작동하는지 확인하는 가장 좋은 방법은 업그레이드 프로세스를 시작하기 전에 좋은 test coverage를 확보하는 것입니다. 애플리케이션의 대부분을 실행하는 자동화된 테스트가 없다면, 변경된 모든 부분을 수동으로 테스트하는 데 시간을 투자해야 할 것입니다. Rails 업그레이드의 경우, 이는 애플리케이션의 모든 기능을 의미합니다. 업그레이드를 시작하기 전에 test coverage가 충분한지 확인하여 자신을 위한 선택을 하세요.

1.2 Ruby 버전

Rails는 일반적으로 새로 출시된 Ruby 버전을 긴밀하게 따릅니다:

  • Rails 8.0은 Ruby 3.2.0 이상이 필요합니다.
  • Rails 7.2는 Ruby 3.1.0 이상이 필요합니다.
  • Rails 7.0과 7.1은 Ruby 2.7.0 이상이 필요합니다.
  • Rails 6은 Ruby 2.5.0 이상이 필요합니다.
  • Rails 5는 Ruby 2.2.2 이상이 필요합니다.

Ruby와 Rails를 따로 업그레이드하는 것이 좋습니다. 먼저 가능한 최신 Ruby 버전으로 업그레이드한 다음, Rails를 업그레이드하세요.

1.3 업그레이드 프로세스

Rails 버전을 변경할 때는 deprecation 경고를 효과적으로 활용하기 위해 한 번에 하나의 minor 버전씩 천천히 진행하는 것이 좋습니다. Rails 버전 번호는 Major.Minor.Patch 형식입니다. Major와 Minor 버전은 public API를 변경할 수 있으므로 애플리케이션에 오류가 발생할 수 있습니다. Patch 버전은 버그 수정만 포함하며 public API를 변경하지 않습니다.

프로세스는 다음과 같이 진행해야 합니다:

  1. 테스트를 작성하고 통과하는지 확인합니다.
  2. 현재 버전 이후의 최신 patch 버전으로 이동합니다.
  3. 테스트와 deprecated된 기능들을 수정합니다.
  4. 다음 minor 버전의 최신 patch 버전으로 이동합니다.

목표로 하는 Rails 버전에 도달할 때까지 이 프로세스를 반복합니다.

1.3.1 버전 간 이동

버전 간 이동하려면:

  1. Gemfile의 Rails 버전 번호를 변경하고 bundle update rails를 실행합니다.
  2. jsbundling-rails를 실행 중인 경우 package.json의 Rails JavaScript 패키지 버전을 변경하고 bin/rails javascript:install을 실행합니다.
  3. Update task를 실행합니다.
  4. 테스트를 실행합니다.

모든 배포된 Rails gem 목록은 여기에서 찾을 수 있습니다.

1.4 Update 작업

Rails는 rails app:update 명령어를 제공합니다. Gemfile에서 Rails 버전을 업데이트한 후에 이 명령어를 실행하세요. 이 명령어는 대화형 세션을 통해 새로운 파일 생성과 기존 파일의 변경을 도와줍니다.

$ bin/rails app:update
       exist  config
    conflict  config/application.rb
/myapp/config/application.rb를 덮어쓰시겠습니까? (도움말은 "h" 입력) [Ynaqdh]
       force  config/application.rb 
      create  config/initializers/new_framework_defaults_8_0.rb
...

diff와 merge 도중 예상치 못한 변경사항이 있었는지 차이점을 검토하는 것을 잊지 마세요. 이 과정에서 사용되는 diff와 merge 도구는 THOR_DIFFTHOR_MERGE 환경 변수를 사용하여 정의할 수 있다는 점을 기억하세요.

1.5 Framework 기본값 설정

새로운 Rails 버전은 이전 버전과 다른 기본 설정 값을 가질 수 있습니다. 하지만 위에서 설명한 단계를 따른 후에도, 애플리케이션은 여전히 이전 Rails 버전의 기본 설정으로 실행될 것입니다. 이는 config/application.rbconfig.load_defaults 값이 아직 변경되지 않았기 때문입니다.

새로운 기본값으로 하나씩 업그레이드할 수 있도록, update 작업은 config/initializers/new_framework_defaults_X_Y.rb 파일을 생성했습니다(파일명에 원하는 Rails 버전 포함). 파일 내의 주석을 해제하여 새로운 기본 설정을 활성화해야 합니다. 이는 여러 번의 배포를 거쳐 점진적으로 수행할 수 있습니다. 애플리케이션이 새로운 기본값으로 실행될 준비가 되면, 이 파일을 제거하고 config.load_defaults 값을 변경할 수 있습니다.

2 Rails 8.0에서 Rails 8.1로 업그레이드

Rails 8.1에서 변경된 사항에 대한 자세한 내용은 릴리스 노트를 참조하세요.

3 Rails 7.2에서 Rails 8.0으로 업그레이드

Rails 8.0에서 변경된 사항에 대한 자세한 내용은 릴리스 노트를 참조하세요.

4 Rails 7.1에서 Rails 7.2로 업그레이드

Rails 7.2에서 변경된 사항에 대한 자세한 내용은 릴리스 노트를 참조하세요.

4.1 모든 테스트가 이제 active_job.queue_adapter 설정을 준수합니다

config/application.rb 또는 config/environments/test.rb 파일에서 config.active_job.queue_adapter를 설정한 경우, 이전에는 선택한 adapter가 모든 테스트에서 일관되게 사용되지 않았습니다. 일부 테스트에서는 설정한 adapter가 사용되었지만, 다른 테스트에서는 TestAdapter가 사용되었습니다.

Rails 7.2에서는 모든 테스트가 제공된 queue_adapter 설정을 준수합니다. 만약 queue_adapter 설정을 :test가 아닌 다른 것으로 설정했지만, TestAdapter에 의존하는 방식으로 테스트를 작성한 경우 테스트 오류가 발생할 수 있습니다.

설정이 제공되지 않은 경우에는 계속해서 TestAdapter가 사용됩니다.

5 Rails 7.0에서 Rails 7.1로 업그레이드

Rails 7.1의 변경사항에 대한 자세한 내용은 릴리스 노트를 참조하세요.

5.1 Development 및 test 환경의 secret_key_base 파일 변경

Development 및 test 환경에서 Rails가 secret_key_base를 읽는 파일이 tmp/development_secret.txt에서 tmp/local_secret.txt로 이름이 변경되었습니다.

동일한 secret을 계속 사용하려면 이전 파일의 이름을 local_secret.txt로 변경하거나, 이전 파일의 키를 새 파일로 복사하면 됩니다.

이렇게 하지 않으면 앱이 로드될 때 Rails가 새로운 파일 tmp/local_secret.txt에 새로운 secret key를 생성합니다.

이로 인해 development 및 test 환경의 모든 기존 세션/쿠키가 무효화되며, Active Storage/Action Text 첨부파일과 같이 secret_key_base로부터 파생된 다른 서명들도 작동하지 않게 됩니다.

Production 및 기타 환경은 영향을 받지 않습니다.

5.2 Autoload된 경로는 더 이상 $LOAD_PATH에 포함되지 않습니다

Rails 7.1부터 autoloader가 관리하는 디렉토리들은 더 이상 $LOAD_PATH에 추가되지 않습니다. 이는 수동으로 require 호출을 통해 이러한 파일들을 로드할 수 없다는 것을 의미하며, 어차피 그렇게 해서는 안 됩니다.

$LOAD_PATH의 크기를 줄이면 bootsnap을 사용하지 않는 앱의 경우 require 호출 속도가 빨라지고, bootsnap을 사용하는 앱의 경우 bootsnap 캐시의 크기가 줄어듭니다.

만약 이러한 경로들을 여전히 $LOAD_PATH에 포함시키고 싶다면, 다음과 같이 opt-in할 수 있습니다:

config.add_autoload_paths_to_load_path = true

Rails가 $LOAD_PATH에 autoload path들을 추가할지 여부를 설정합니다.

오래된 코드와의 호환성을 위해서는 true로 설정해야 할 수 있습니다만, 기본값은 false입니다.

이것은 Zeitwerk mode가 활성화되었을 때만 적용됩니다.

하지만 우리는 그렇게 하는 것을 권장하지 않습니다. autoload paths에 있는 클래스와 모듈은 autoload되도록 설계되어 있습니다. 즉, 단순히 참조만 하면 됩니다.

lib 디렉토리는 이 설정의 영향을 받지 않으며, 항상 $LOAD_PATH에 추가됩니다.

5.3 config.autoload_lib 및 config.autoload_lib_once

애플리케이션에서 lib 디렉토리가 autoload 또는 autoload once 경로에 포함되어 있지 않다면, 이 섹션을 건너뛰세요. 아래의 명령어 출력을 통해 확인할 수 있습니다.

# autoload 경로를 출력합니다.
$ bin/rails runner 'pp Rails.autoloaders.main.dirs'

# autoload once 경로를 출력합니다.
$ bin/rails runner 'pp Rails.autoloaders.once.dirs'

애플리케이션이 autoload paths에 이미 lib를 가지고 있다면, 일반적으로 config/application.rb에 다음과 같은 configuration이 있습니다

# lib 디렉터리를 autoload하되, eager load는 하지 않습니다 (간과될 수 있음).
config.autoload_paths << config.root.join("lib")

또는

# lib를 autoload하고 eager load도 합니다.
config.autoload_paths << config.root.join("lib")  
config.eager_load_paths << config.root.join("lib")

or

# eager load path 들은 모두 autoload path 가 되므로 같은 결과입니다.
config.eager_load_paths << config.root.join("lib")

이것도 여전히 작동하지만, 이러한 코드를 더 간결한 코드로 대체하는 것이 권장됩니다

config.autoload_lib(ignore: %w(assets tasks))

lib 디렉토리를 autoload path에 추가하면서, 'assets'와 'tasks' 서브디렉토리는 제외합니다.

lib 하위 디렉토리 중에서 .rb 파일을 포함하지 않거나 reload 또는 eager load가 필요하지 않은 디렉토리는 ignore 리스트에 추가해주세요. 예를 들어, 애플리케이션에 lib/templates, lib/generators, 또는 lib/middleware가 있다면, lib를 기준으로 한 상대 경로로 이름을 추가하면 됩니다:

lib 디렉터리의 자동 로딩 설정이지만, %w(assets tasks templates generators middleware) 디렉터리들은 제외합니다.

이 한 줄의 코드로 config.eager_loadtrue인 경우(production 모드에서 기본값) lib 폴더 내의 (무시되지 않은) 코드도 eager load될 것입니다. 이는 일반적으로 원하는 동작이지만, 만약 lib가 이전에 eager load paths에 추가되지 않았고 그대로 유지하고 싶다면 다음과 같이 opt-out할 수 있습니다:

Rails.autoloaders.main.do_not_eager_load(config.root.join("lib"))

lib 디렉터리를 eager loading에서 제외합니다.

config.autoload_lib_once 메소드는 애플리케이션이 config.autoload_once_pathslib를 포함하고 있을 때의 동일한 역할을 하는 메소드입니다.

5.4 ActiveStorage::BaseController가 더 이상 streaming concern을 포함하지 않음

커스텀 파일 제공 로직을 구현하기 위해 streaming을 사용하고 ActiveStorage::BaseController를 상속하는 application controller는 이제 명시적으로 ActiveStorage::Streaming module을 포함해야 합니다.

5.5 MemCacheStoreRedisCacheStore가 이제 기본적으로 connection pooling을 사용합니다

connection_pool gem이 activesupport gem의 의존성으로 추가되었으며, MemCacheStoreRedisCacheStore는 이제 기본적으로 connection pooling을 사용합니다.

connection pooling을 사용하지 않으려면, cache store를 구성할 때 :pool 옵션을 false로 설정하세요:

config.cache_store = :mem_cache_store, "cache.example.com", { pool: false }

Rails에서의 캐싱 가이드에서 더 자세한 정보를 확인하세요.

5.6 SQLite3Adapter가 이제 strict strings 모드에서 사용되도록 설정됨

strict strings 모드의 사용으로 큰따옴표로 된 문자열 리터럴이 비활성화됩니다.

SQLite는 큰따옴표로 된 문자열 리터럴과 관련해 몇 가지 특이사항이 있습니다. 먼저 큰따옴표로 된 문자열을 식별자 이름으로 간주하려고 시도하지만, 해당 식별자가 존재하지 않으면 문자열 리터럴로 간주합니다. 이로 인해 오타가 조용히 간과될 수 있습니다. 예를 들어, 존재하지 않는 컬럼에 대한 인덱스를 생성하는 것이 가능합니다. 자세한 내용은 SQLite 문서를 참조하세요.

SQLite3Adapter를 strict 모드에서 사용하지 않으려면 이 동작을 비활성화할 수 있습니다:

# config/application.rb
config.active_record.sqlite3_adapter_strict_strings_by_default = false

SQLite adapter가 string literals를 strict하게 취급할지 여부를 지정합니다. false로 설정하면 legacy behavior가 유지됩니다. SQLite에서 'foo' = "foo"와 같은 비교가 가능해집니다.

5.7 ActionMailer::Preview를 위한 다중 미리보기 경로 지원

config.action_mailer.preview_path 옵션은 config.action_mailer.preview_paths로 대체되었습니다. 이 설정 옵션에 경로를 추가하면 mailer preview를 검색할 때 해당 경로들이 사용됩니다.

config.action_mailer.preview_paths << "#{Rails.root}/lib/mailer_previews"

메일러 preview 파일을 검색할 추가 경로를 지정합니다.

5.8 config.i18n.raise_on_missing_translations = true가 이제 누락된 모든 번역에서 예외를 발생시킵니다.

이전에는 view나 controller에서 호출될 때만 예외가 발생했습니다. 이제는 I18n.t에 인식되지 않는 키가 제공될 때마다 예외가 발생합니다.

# config.i18n.raise_on_missing_translations = true 설정 시

# view나 controller에서:
t("missing.key") # 7.0에서 예외 발생, 7.1에서 예외 발생
I18n.t("missing.key") # 7.0에서 예외 발생하지 않음, 7.1에서 예외 발생

# 어디에서든:
I18n.t("missing.key") # 7.0에서 예외 발생하지 않음, 7.1에서 예외 발생

이 동작을 원하지 않는다면, config.i18n.raise_on_missing_translations = false로 설정할 수 있습니다:

# config.i18n.raise_on_missing_translations = false 설정과 함께

# view나 controller에서:
t("missing.key") # 7.0에서 raise하지 않았고, 7.1에서도 raise하지 않음
I18n.t("missing.key") # 7.0에서 raise하지 않았고, 7.1에서도 raise하지 않음

# 어디서든:
I18n.t("missing.key") # 7.0에서 raise하지 않았고, 7.1에서도 raise하지 않음

또는 I18n.exception_handler를 커스터마이즈할 수 있습니다. 자세한 내용은 i18n 가이드를 참조하세요.

AbstractController::Translation.raise_on_missing_translations는 제거되었습니다. 이는 private API였으며, 만약 이를 사용하고 있었다면 config.i18n.raise_on_missing_translations 또는 커스텀 exception handler로 마이그레이션해야 합니다.

5.9 bin/rails test가 이제 test:prepare 태스크를 실행합니다

bin/rails test로 테스트를 실행할 때, 테스트가 실행되기 전에 rake test:prepare 태스크가 실행됩니다. 만약 test:prepare 태스크를 강화했다면, 테스트 실행 전에 해당 강화된 기능들이 실행될 것입니다. tailwindcss-rails, jsbundling-rails, cssbundling-rails와 다른 서드파티 gem들이 이 태스크를 강화합니다.

자세한 내용은 Testing Rails Applications 가이드를 참고하세요.

단일 파일의 테스트를 실행할 경우(bin/rails test test/models/user_test.rb), 실행 전에 test:prepare가 실행되지 않습니다.

5.10 @rails/ujs의 import 구문이 수정됨

Rails 7.1부터 @rails/ujs에서 모듈을 import하는 구문이 수정되었습니다. Rails는 더 이상 @rails/ujs에서 모듈을 직접 import하는 것을 지원하지 않습니다.

예를 들어, 라이브러리에서 함수를 import하려고 하면 실패할 것입니다:

import { fileInputSelector } from "@rails/ujs"
// 에러: '@rails/ujs'에서 'fileInputSelector'를 찾을 수 없습니다 (가능한 exports: default)

Rails 7.1에서는 사용자가 먼저 Rails 객체를 @rails/ujs에서 직접 import 해야 합니다. 그런 다음 사용자는 Rails 객체에서 특정 모듈을 import 할 수 있습니다.

Rails 7.1의 import 예시는 다음과 같습니다:

import Rails from "@rails/ujs"
// 메서드 별칭 지정
const fileInputSelector = Rails.fileInputSelector
// 또는 사용되는 Rails 객체에서 직접 참조
Rails.fileInputSelector(...)

5.11 Rails.logger가 이제 ActiveSupport::BroadcastLogger 인스턴스를 반환합니다

ActiveSupport::BroadcastLogger 클래스는 로그를 다양한 싱크(STDOUT, 로그 파일...)로 쉽게 브로드캐스트할 수 있게 해주는 새로운 logger입니다.

로그를 브로드캐스트하는 API(ActiveSupport::Logger.broadcast 메서드 사용)는 이전에 private이었으며 제거되었습니다. 만약 애플리케이션이나 라이브러리가 이 API에 의존하고 있었다면, 다음과 같은 변경이 필요합니다:

logger = Logger.new("some_file.log") 

# Before(변경 전)

Rails.logger.extend(ActiveSupport::Logger.broadcast(logger))

# After(변경 후)

Rails.logger.broadcast_to(logger)

애플리케이션에서 커스텀 logger를 구성했다면, Rails.logger는 모든 메서드를 래핑하고 프록시합니다. 이를 작동시키기 위해 별도의 변경이 필요하지 않습니다.

커스텀 logger 인스턴스에 접근해야 한다면, broadcasts 메서드를 사용하면 됩니다:

# config/application.rb
config.logger = MyLogger.new

# 애플리케이션 내 어디서나
puts Rails.logger.class #=> BroadcastLogger
puts Rails.logger.broadcasts #=> [MyLogger]

[assert_match][assert_match]

5.12 Active Record Encryption 알고리즘 변경사항

Active Record Encryption은 이제 해시 다이제스트 알고리즘으로 SHA-256을 사용합니다. 이전 Rails 버전에서 암호화된 데이터가 있다면, 다음 두 가지 시나리오를 고려해야 합니다:

  1. config.active_support.key_generator_hash_digest_class가 SHA-1(Rails 7.0 이전의 기본값)로 설정되어 있다면, Active Record Encryption에도 SHA-1을 설정해야 합니다:

    config.active_record.encryption.hash_digest_class = OpenSSL::Digest::SHA1
    

    모든 데이터가 비결정적으로 암호화되었다면(deterministric: true로 encrypts를 전달하지 않은 기본값), 대신 아래 시나리오 2처럼 Active Record Encryption에 SHA-256을 설정하고 다음 설정을 통해 이전에 SHA-1으로 암호화된 컬럼의 복호화를 허용할 수 있습니다:

    config.active_record.encryption.support_sha1_for_non_deterministic_encryption = true
    
  2. config.active_support.key_generator_hash_digest_class가 SHA-256(7.0의 새로운 기본값)으로 설정되어 있다면, Active Record Encryption에도 SHA-256을 설정해야 합니다:

    config.active_record.encryption.hash_digest_class = OpenSSL::Digest::SHA256
    

config.active_record.encryption.hash_digest_class에 대한 자세한 내용은 Rails 애플리케이션 설정하기 가이드를 참조하세요.

추가로, 앞서 언급한 hash_digest_class 설정을 통해 SHA-256이 설정되어 있을 때도 일부 속성이 SHA-1로 암호화되는 버그를 해결하기 위해 새로운 설정 config.active_record.encryption.support_sha1_for_non_deterministic_encryption이 도입되었습니다.

기본적으로 Rails 7.1에서는 config.active_record.encryption.support_sha1_for_non_deterministic_encryption가 비활성화되어 있습니다. Rails 7.1 미만 버전에서 암호화된 데이터가 있고 앞서 언급한 버그의 영향을 받았을 것으로 생각된다면, 이 설정을 활성화해야 합니다:

config.active_record.encryption.support_sha1_for_non_deterministic_encryption = true

비결정적 암호화의 경우 SHA1 Hash를 지원하도록 활성화합니다.

암호화된 데이터를 다루고 있다면, 위의 내용을 주의 깊게 검토해주세요.

5.13 Controller Tests, Integration Tests 및 System Tests에서 예외를 처리하는 새로운 방법

config.action_dispatch.show_exceptions 설정은 Action Pack이 요청에 응답하는 동안 발생한 예외를 처리하는 방식을 제어합니다.

Rails 7.1 이전에는 config.action_dispatch.show_exceptions = true를 설정하면 Action Pack이 예외를 포착하고 적절한 HTML 오류 페이지를 렌더링하도록 구성되었습니다. 예를 들어 ActiveRecord::RecordNotFound 예외를 발생시키는 대신 404 Not found 상태 코드와 함께 public/404.html을 렌더링하는 식입니다. config.action_dispatch.show_exceptions = false를 설정하면 Action Pack이 예외를 포착하지 않도록 구성되었습니다. Rails 7.1 이전에는 새 애플리케이션이 생성될 때 config/environments/test.rbconfig.action_dispatch.show_exceptions = false를 설정하는 코드가 포함되어 있었습니다.

Rails 7.1은 허용되는 값을 truefalse에서 :all, :rescuable, :none으로 변경했습니다.

  • :all - 모든 예외에 대해 HTML 오류 페이지를 렌더링 (true와 동일)
  • :rescuable - config.action_dispatch.rescue_responses에 선언된 예외에 대해 HTML 오류 페이지를 렌더링
  • :none (false와 동일) - 어떤 예외도 포착하지 않음

Rails 7.1 이후 생성된 애플리케이션은 config/environments/test.rb에서 config.action_dispatch.show_exceptions = :rescuable을 설정합니다. 업그레이드 시 기존 애플리케이션은 새로운 동작을 사용하기 위해 config.action_dispatch.show_exceptions = :rescuable로 변경하거나, 기존 값을 해당하는 새 값으로 대체할 수 있습니다(true:all로, false:none으로 대체).

6 Rails 6.1에서 Rails 7.0으로 업그레이드

Rails 7.0의 변경 사항에 대한 자세한 내용은 릴리스 노트를 참조하세요.

6.1 ActionView::Helpers::UrlHelper#button_to 동작 변경

Rails 7.0부터 button_to는 영속된 Active Record 객체가 버튼 URL을 생성하는 데 사용될 경우 patch HTTP verb와 함께 form 태그를 렌더링합니다. 현재 동작을 유지하려면 method: 옵션을 명시적으로 전달하는 것을 고려하세요:

-button_to("POST 실행하기", [:my_custom_post_action_on_workshop, Workshop.find(1)])
+button_to("POST 실행하기", [:my_custom_post_action_on_workshop, Workshop.find(1)], method: :post)

또는 helper를 사용하여 URL을 만듭니다:

-button_to("POST 실행", [:my_custom_post_action_on_workshop, Workshop.find(1)])
+button_to("POST 실행", my_custom_post_action_on_workshop_workshop_path(Workshop.find(1)))

6.2 Spring

애플리케이션이 Spring을 사용하는 경우, 최소 3.0.0 버전으로 업그레이드해야 합니다. 그렇지 않으면

`mechanism=`가 ActiveSupport::Dependencies:Module에 대해 정의되지 않은 메서드

또한, config/environments/test.rb에서 config.cache_classesfalse로 설정되어 있는지 확인하세요.

6.3 Sprockets는 이제 선택적 의존성입니다

rails gem은 더 이상 sprockets-rails에 의존하지 않습니다. 애플리케이션에서 여전히 Sprockets를 사용해야 하는 경우, Gemfile에 sprockets-rails를 추가하세요.

gem "sprockets-rails"

6.4 애플리케이션은 zeitwerk 모드로 실행되어야 합니다

classic 모드로 실행 중인 애플리케이션은 zeitwerk 모드로 전환해야 합니다. 자세한 내용은 Classic to Zeitwerk HOWTO 가이드를 참조하세요.

6.5 setter config.autoloader=가 삭제되었습니다

Rails 7에서는 autoloading 모드를 설정하는 설정점이 없어졌으며, config.autoloader=가 삭제되었습니다. 어떤 이유로든 :zeitwerk로 설정했다면, 그냥 제거하면 됩니다.

6.6 ActiveSupport::Dependencies private API가 삭제됨

ActiveSupport::Dependencies의 private API가 삭제되었습니다. 여기에는 hook!, unhook!, depend_on, require_or_load, mechanism 등의 메서드들이 포함됩니다.

주요 변경사항:

  • ActiveSupport::Dependencies.constantize 또는 ActiveSupport::Dependencies.safe_constantize를 사용했다면, 단순히 String#constantize 또는 String#safe_constantize로 변경하세요.
  ActiveSupport::Dependencies.constantize("User") # 더 이상 사용 불가
  "User".constantize # 👍
  • ActiveSupport::Dependencies.mechanism의 읽기 또는 쓰기 사용은 config.cache_classes를 적절히 접근하는 것으로 대체되어야 합니다.

  • autoloader의 활동을 추적하고 싶다면, ActiveSupport::Dependencies.verbose=는 더 이상 사용할 수 없으며, config/application.rbRails.autoloaders.log!를 추가하면 됩니다.

ActiveSupport::Dependencies::Reference, ActiveSupport::Dependencies::Blamable 등과 같은 보조 내부 클래스나 모듈들도 함께 삭제되었습니다.

6.7 초기화 중 Autoloading

to_prepare 블록 외부에서 초기화 중에 reloadable 상수를 autoload한 애플리케이션은 Rails 6.0부터 해당 상수가 unload되고 이러한 경고가 발생했습니다:

DEPRECATION WARNING: 초기화 시에 상수 를 자동으로 로드했습니다 ....

이런 방식은 더 이상 권장되지 않습니다. 초기화 중의 autoloading은 
향후 Rails 버전에서 에러가 발생하게 될 것입니다.

...

만약 로그에서 이 warning이 계속 보인다면, autoloading guide의 애플리케이션 부팅 시 autoloading에 대한 섹션을 확인해주세요. 그렇지 않으면 Rails 7에서 NameError가 발생할 것입니다.

once autoloader가 관리하는 Constants는 초기화 중에 autoload 될 수 있으며, to_prepare 블록 없이도 정상적으로 사용할 수 있습니다. 하지만 이를 지원하기 위해 once autoloader가 이제 더 일찍 설정됩니다. 애플리케이션에 custom inflections이 있고 once autoloader가 이를 인식해야 하는 경우, config/initializers/inflections.rb의 코드를 config/application.rb의 애플리케이션 클래스 정의 본문으로 이동해야 합니다:

module MyApp
  class Application < Rails::Application
    # ...

    ActiveSupport::Inflector.inflections(:en) do |inflect|
      inflect.acronym "HTML" # HTML과 같은 약어가 포함된 문자열을 변환할 때 약어 형태를 유지하도록 지정
    end
  end
end

6.8 config.autoload_once_paths 구성 기능

config.autoload_once_pathsconfig/application.rb에 정의된 application 클래스의 body 또는 config/environments/*의 환경 설정에서 설정할 수 있습니다.

마찬가지로 engine은 engine 클래스의 body나 환경 설정에서 해당 컬렉션을 구성할 수 있습니다.

그 후에는 컬렉션이 freeze되며, 이러한 경로에서 autoload할 수 있습니다. 특히 초기화 중에도 이러한 경로에서 autoload할 수 있습니다. 이들은 reload하지 않고 autoload/eager load만 수행하는 Rails.autoloaders.once autoloader에 의해 관리됩니다.

환경 설정이 처리된 후에 이 설정을 구성했고 FrozenError가 발생하는 경우, 코드 위치만 이동하면 됩니다.

6.9 ActionDispatch::Request#content_type은 이제 Content-Type 헤더를 있는 그대로 반환합니다.

이전에는 ActionDispatch::Request#content_type이 반환하는 값이 charset 부분을 포함하지 않았습니다. 이 동작이 변경되어 Content-Type 헤더의 charset 부분을 있는 그대로 포함하여 반환하게 되었습니다.

만약 MIME type만 필요하다면, 대신 ActionDispatch::Request#media_type을 사용하세요.

이전:

request = ActionDispatch::Request.new("CONTENT_TYPE" => "text/csv; header=present; charset=utf-16", "REQUEST_METHOD" => "GET") 
request.content_type #=> "text/csv"

죄송하지만 번역할 문서가 공유되지 않았습니다. Rails 가이드 문서를 공유해주시면 요청하신대로 번역을 도와드리겠습니다.

request = ActionDispatch::Request.new("Content-Type" => "text/csv; header=present; charset=utf-16", "REQUEST_METHOD" => "GET") 
request.content_type #=> "text/csv; header=present; charset=utf-16" 
request.media_type   #=> "text/csv"

Key generator의 기본 digest class가 SHA1에서 SHA256으로 변경됩니다. 이는 암호화된 쿠키를 포함하여 Rails에서 생성된 모든 암호화 메시지에 영향을 미칩니다.

이전 digest class를 사용하여 메시지를 읽으려면 rotator를 등록해야 합니다. 이를 하지 않으면 업그레이드 중에 사용자의 세션이 무효화될 수 있습니다.

다음은 암호화된 쿠키와 서명된 쿠키를 위한 rotator의 예시입니다.

config/initializers/cookie_rotator.rb

Rails.application.config.after_initialize do Rails.application.config.action_dispatch.cookies_rotations.tap do |cookies| authenticated_encrypted_cookie_salt = Rails.application.config.action_dispatch.authenticated_encrypted_cookie_salt signed_cookie_salt = Rails.application.config.action_dispatch.signed_cookie_salt

secret_key_base = Rails.application.secret_key_base

key_generator = ActiveSupport::KeyGenerator.new(
  secret_key_base, iterations: 1000, hash_digest_class: OpenSSL::Digest::SHA1
)
key_len = ActiveSupport::MessageEncryptor.key_len

old_encrypted_secret = key_generator.generate_key(authenticated_encrypted_cookie_salt, key_len)
old_signed_secret = key_generator.generate_key(signed_cookie_salt)

cookies.rotate :encrypted, old_encrypted_secret
cookies.rotate :signed, old_signed_secret

end end

6.11 ActiveSupport::Digest의 Digest class가 SHA256으로 변경됨

ActiveSupport::Digest의 기본 digest class가 SHA1에서 SHA256으로 변경되었습니다. 이는 Etag와 같은 것들의 변경과 캐시 키에도 영향을 미칩니다. 이러한 키들의 변경은 캐시 적중률에 영향을 줄 수 있으므로, 새로운 해시로 업그레이드할 때 주의하고 이를 주시해야 합니다.

6.12 새로운 ActiveSupport::Cache 직렬화 형식

더 빠르고 더 간단한 직렬화 형식이 도입되었습니다.

이를 활성화하려면 config.active_support.cache_format_version = 7.0을 설정해야 합니다:

# config/application.rb

config.load_defaults 6.1
config.active_support.cache_format_version = 7.0

Or simply로만 되어있어서 번역할 내용이 부족합니다. 전체 문장이나 단락을 제공해주시면 번역해드리겠습니다.

# config/application.rb

config.load_defaults 7.0

주어진 버전의 기본값들을 로드합니다. 이 설정은 새로 생성된 애플리케이션에 기본으로 포함되어 있으며 Rails의 다음 버전에서 일관된 기능을 얻기 위해 이전 버전의 기본값을 가져올 수 있게 해줍니다.

그러나 Rails 6.1 애플리케이션은 이 새로운 serialization 포맷을 읽을 수 없습니다. 따라서 원활한 업그레이드를 위해서는 먼저 config.active_support.cache_format_version = 6.1로 Rails 7.0 업그레이드를 배포해야 하며, 모든 Rails 프로세스가 업데이트된 후에만 config.active_support.cache_format_version = 7.0으로 설정할 수 있습니다.

Rails 7.0은 두 가지 포맷을 모두 읽을 수 있으므로 업그레이드 중에 캐시가 무효화되지 않습니다.

6.13 Active Storage 비디오 미리보기 이미지 생성

비디오 미리보기 이미지 생성이 이제 FFmpeg의 장면 변화 감지 기능을 사용하여 더 의미 있는 미리보기 이미지를 생성합니다. 이전에는 비디오의 첫 번째 프레임이 사용되었고, 이는 비디오가 검은색에서 페이드 인되는 경우 문제가 되었습니다. 이 변경사항을 적용하려면 FFmpeg v3.4+ 버전이 필요합니다.

6.14 Active Storage 기본 variant processor가 :vips로 변경됨

새로운 앱의 경우, 이미지 변환 시 ImageMagick 대신 libvips를 사용합니다. 이를 통해 variant를 생성하는 데 걸리는 시간과 CPU 및 메모리 사용량이 감소되어, 이미지 제공을 위해 Active Storage를 사용하는 앱의 응답 시간이 개선됩니다.

:mini_magick 옵션은 deprecate되지 않으므로 계속 사용해도 무방합니다.

기존 앱을 libvips로 마이그레이션하려면 다음과 같이 설정하세요:

Rails.application.config.active_storage.variant_processor = :vips

그런 다음 기존의 이미지 변환 코드를 image_processing 매크로로 변경하고, ImageMagick의 옵션을 libvips의 옵션으로 교체해야 합니다.

6.14.1 resize를 resize_to_limit로 교체

- variant(resize: "100x")
+ variant(resize_to_limit: [100, nil])

crop할 때 array를 사용하지 않으면, vips로 전환할 때 다음과 같은 에러가 발생합니다: no implicit conversion to float from string.

6.14.2 crop할 때는 array를 사용하세요

- variant(crop: "1920x1080+0+0")
+ variant(crop: [0, 0, 1920, 1080])
vips로 마이그레이션할 때 이를 수행하지 않으면 `unable to call crop: you supplied 2 arguments, but operation needs 5` 에러가 발생합니다.

#### 크롭 값 제한하기:

Vips는 ImageMagick보다 크로핑에 대해 더 엄격합니다:

1. `x` 및/또는 `y`가 음수인 경우 크롭하지 않습니다. 예: `[-10, -10, 100, 100]`
2. 위치(`x` 또는 `y`)에 크롭 크기(`width`, `height`)를 더한 값이 이미지보다 큰 경우 크롭하지 않습니다. 예: 125x125 이미지에 `[50, 50, 100, 100]` 크롭

vips로 마이그레이션할 때 이를 수행하지 않으면 `extract_area: bad extract area` 에러가 발생합니다.

#### `resize_and_pad`에 사용되는 배경색 조정하기

Vips는 ImageMagick처럼 흰색이 아닌 검은색을 `resize_and_pad`의 기본 배경색으로 사용합니다. `background` 옵션을 사용하여 이를 수정할 수 있습니다:
- variant(resize_and_pad: [300, 300])
+ variant(resize_and_pad: [300, 300, background: [255]]) 

6.14.3 EXIF 기반 회전 제거

Vips는 variant를 처리할 때 EXIF 값을 사용하여 이미지를 자동으로 회전합니다. 만약 ImageMagick을 사용하여 회전을 적용하기 위해 사용자가 업로드한 사진의 회전 값을 저장하고 있었다면, 이제는 그렇게 하지 말아야 합니다:

- variant(format: :jpg, rotate: rotation_value) 
+ variant(format: :jpg)

6.14.4 monochrome를 colorspace로 대체하기

Vips는 단색(monochrome) 이미지를 만들기 위해 다른 옵션을 사용합니다:

- variant(monochrome: true) 
+ variant(colourspace: "b-w")

6.14.5 libvips 옵션으로 전환하여 이미지 압축하기

JPEG

- variant(strip: true, quality: 80, interlace: "JPEG", sampling_factor: "4:2:0", colorspace: "sRGB")
+ variant(saver: { strip: true, quality: 80, interlace: true })

경고: 불완전한 지침입니다. 번역할 Rails 가이드 문서의 실제 내용이 제공되지 않았습니다. 번역을 도와드리려면 완전한 영문 원문을 공유해 주시기 바랍니다.

- variant(strip: true, quality: 75)
+ variant(saver: { strip: true, compression: 9 })

죄송하지만 번역할 내용이 보이지 않습니다. Rails 가이드 문서를 공유해주시면 번역을 도와드리도록 하겠습니다.

- variant(strip: true, quality: 75, define: { webp: { lossless: false, alpha_quality: 85, thread_level: 1 } })
+ variant(saver: { strip: true, quality: 75, lossless: false, alpha_q: 85, reduction_effort: 6, smart_subsample: true })

GIF

- variant(layers: "Optimize")
+ variant(saver: { optimize_gif_frames: true, optimize_gif_transparency: true })

6.14.6 프로덕션 배포

Active Storage는 이미지 URL에 수행되어야 할 transformation 목록을 인코딩합니다. 앱이 이러한 URL들을 캐싱하는 경우, 새로운 코드를 프로덕션에 배포한 후 이미지가 깨질 수 있습니다. 이러한 이유로 영향을 받는 캐시 키를 수동으로 무효화해야 합니다.

예를 들어, 뷰에서 다음과 같은 코드가 있다면:

<% @products.each do |product| %>
  <% cache product do %>
    <%= image_tag product.cover_photo.variant(resize: "200x") %>
  <% end %>
<% end %>

제품을 touch하거나 cache key를 변경하여 cache를 무효화할 수 있습니다:

<% @products.each do |product| %>
  <% cache ["v2", product] do %>
    <%= image_tag product.cover_photo.variant(resize_to_limit: [200, nil]) %>
  <% end %>
<% end %>

6.15 스키마 덤프에 Rails 버전이 이제 포함됨

Rails 7.0은 일부 컬럼 타입의 기본값을 변경했습니다. Rails 6.1에서 7.0으로 업그레이드하는 애플리케이션이 새로운 7.0 기본값을 사용하여 현재 스키마를 로드하는 것을 방지하기 위해, Rails는 이제 스키마 덤프에 프레임워크의 버전을 포함합니다.

Rails 7.0에서 처음으로 스키마를 로드하기 전에, 스키마 덤프에 버전이 포함되도록 rails app:update를 실행하십시오.

스키마 파일은 다음과 같이 보일 것입니다:

# 이 파일은 현재 데이터베이스 상태로부터 자동 생성됩니다. 이 파일을 직접 
# 수정하는 대신, Active Record의 migration 기능을 사용하여 점진적으로 데이터베이스를
# 수정하고, schema 정의를 재생성하세요.
#
# 이 파일은 `bin/rails db:schema:load` 실행 시 Rails가 schema를 정의하는데 사용하는 소스입니다. 
# 새로운 데이터베이스를 만들 때 `bin/rails db:schema:load`는 migration을 처음부터 실행하는 것보다 
# 더 빠르고 잠재적으로 오류가 적습니다. 외부 의존성이나 애플리케이션 코드를 사용하는 
# 오래된 migration은 올바르게 적용되지 않을 수 있습니다.
#
# 이 파일을 version control system에 체크인하는 것을 강력히 권장합니다.

ActiveRecord::Schema[6.1].define(version: 2022_01_28_123512) do
  # ...
end

Rails 7.0에서 처음으로 schema를 dump할 때, column 정보를 포함하여 해당 파일에 많은 변경사항이 보일 것입니다. 새로운 schema 파일의 내용을 검토하고 repository에 commit하시기 바랍니다.

7 Rails 6.0에서 Rails 6.1로 업그레이드

Rails 6.1에서 이루어진 변경사항에 대한 자세한 내용은 릴리스 노트를 참조하세요.

7.1 Rails.application.config_for의 반환 값이 더 이상 String 키를 사용한 접근을 지원하지 않습니다.

다음과 같은 설정 파일이 있다고 가정할 때:

# config/example.yml
development:
  options:
    key: value
Rails.application.config_for(:example).options

이전에는 String 키로 값에 접근할 수 있는 hash를 반환했습니다. 이는 6.0에서 deprecated 되었고 이제는 더 이상 작동하지 않습니다.

String 키로 값에 접근하고 싶다면 config_for의 반환값에 with_indifferent_access를 호출할 수 있습니다. 예:

Rails.application.config_for(:example).with_indifferent_access.dig("options", "key")

7.2 respond_to#any 사용시 Response의 Content-Type

Rails 6.0에서 반환되던 것과 다른 Content-Type 헤더가 응답으로 반환될 수 있습니다. 특히 애플리케이션에서 respond_to { |format| format.any }를 사용하는 경우에 더욱 그렇습니다. Content-Type은 이제 요청의 format이 아닌 주어진 블록을 기반으로 결정됩니다.

예시:

def my_action
  respond_to do |format|
    format.any { render(json: { foo: "bar" }) }
  end
end
get("my_action.csv")

이전 동작은 JSON 응답이 렌더링되고 있음에도 부정확한 text/csv Content-Type을 반환했습니다. 현재 동작은 올바르게 application/json Content-Type을 반환합니다.

만약 애플리케이션이 이전의 잘못된 동작에 의존하고 있다면, 액션이 허용하는 포맷을 명시적으로 지정하는 것을 권장합니다, 예를 들어:

format.any(:xml, :json) { render request.format.to_sym => @people }
  • :xml이나 :json 형식 모두에서 해당 format으로 @people을 렌더링합니다

7.3 ActiveSupport::Callbacks#halted_callback_hook이 이제 두 번째 인자를 받습니다

Active Support는 콜백이 체인을 중단할 때마다 halted_callback_hook을 오버라이드할 수 있게 해줍니다. 이 메소드는 이제 중단된 콜백의 이름인 두 번째 인자를 받습니다. 이 메소드를 오버라이드하는 클래스가 있다면 두 개의 인자를 받도록 수정해야 합니다. 이는 이전 deprecation 주기 없이 이루어지는 breaking change임을 참고하세요(성능상의 이유로).

예시:

class Book < ApplicationRecord
  before_save { throw(:abort) }
  before_create { throw(:abort) }

  def halted_callback_hook(filter, callback_name) # => 이 메서드는 이제 1개 대신 2개의 인자를 받습니다 
    Rails.logger.info("Book이 #{callback_name}될 수 없습니다")
  end
end

7.4 컨트롤러의 helper 클래스 메서드는 String#constantize를 사용

개념적으로, Rails 6.1 이전에는

helper "foo/bar"

일치하는 디렉토리 아래에 정의된 helper를 추가합니다. "foo/bar"는 "app/helpers/foo/bar_helper.rb"를 추가합니다.

resulted in은 ~의 결과를 초래했다, ~을 야기했다 라는 의미입니다.

require_dependency "foo/bar_helper"
module_name = "foo/bar_helper".camelize
module_name.constantize

참고: Rails는 Class/Module.const_missing을 사용하여 자동로딩이 작동하기 때문에 autoload_paths에 있는 파일은 require나 load를 직접 호출해서는 안됩니다. 그러나 해당 파일이 autoload_paths의 파일에 직접 의존하는 경우 require_dependency를 사용할 수 있습니다.

그 예로는 ActiveRecord callbacks가 있습니다. ActiveRecord model이 mixin을 require하고, mixin이 초기화될 때 model에서 attr_accessor를 정의하면, 이러한 accessor는 클래스 정의 시간에 존재해야 하므로 require_dependency가 필요합니다.

이제 다음과 같이 작동합니다:

prefix = "foo/bar".camelize
"#{prefix}Helper".constantize

첫 번째 줄은 "foo/bar"를 camel case로 변환하고 prefix에 저장합니다. 즉, "FooBar"가 됩니다.

두 번째 줄은 문자열 "FooBarHelper"를 만든 후 이것을 상수로 변환합니다. 이는 실제 FooBarHelper 클래스를 찾아 반환하게 됩니다.

이 변경사항은 대부분의 애플리케이션에서 하위 호환성을 유지하므로, 별도의 조치가 필요하지 않습니다.

하지만 기술적으로는, 컨트롤러가 helpers_path를 autoload paths에 포함되지 않은 $LOAD_PATH 내의 디렉터리를 가리키도록 설정할 수 있었습니다. 이러한 사용 사례는 더 이상 기본적으로 지원되지 않습니다. helper 모듈이 autoloadable하지 않은 경우, helper를 호출하기 전에 해당 모듈을 로드하는 것은 애플리케이션의 책임입니다.

7.5 HTTP에서 HTTPS로의 리다이렉션이 이제 308 HTTP 상태 코드를 사용합니다

HTTP에서 HTTPS로 GET/HEAD가 아닌 요청을 리다이렉트할 때 ActionDispatch::SSL에서 사용되는 기본 HTTP 상태 코드가 https://tools.ietf.org/html/rfc7538 에 정의된 대로 308로 변경되었습니다.

7.6 Active Storage가 이제 Image Processing을 필요로 합니다

Active Storage에서 variant를 처리할 때, 이제 mini_magick을 직접 사용하는 대신 image_processing gem을 번들링해야 합니다. Image Processing은 기본적으로 내부적으로 mini_magick을 사용하도록 설정되어 있으므로, 업그레이드하는 가장 쉬운 방법은 mini_magick gem을 image_processing gem으로 교체하고 더 이상 필요하지 않은 combine_options의 명시적 사용을 제거하는 것입니다.

가독성을 위해, 원시 resize 호출을 image_processing 매크로로 변경하는 것이 좋습니다. 예를 들어, 다음과 같은 대신:

video.preview(resize: "100x100") # 강제로 100x100 크기로 이미지 조정
video.preview(resize: "100x100>") # 원본이 더 클 때만 100x100으로 축소
video.preview(resize: "100x100^") # 100x100 영역을 채우도록 이미지 확대

다음과 같이 할 수 있습니다:

video.preview(resize_to_fit: [100, 100]) # 비율을 유지하면서 지정된 크기에 맞추어 축소/확대
video.preview(resize_to_limit: [100, 100]) # 비율을 유지하면서 지정된 크기 이하로만 축소 
video.preview(resize_to_fill: [100, 100]) # 비율과 관계없이 지정된 크기로 변환하고 중앙 기준으로 자르기

7.7 새로운 ActiveModel::Error 클래스

오류는 이제 API가 변경된 새로운 ActiveModel::Error 클래스의 인스턴스입니다. 이러한 변경 사항 중 일부는 오류를 다루는 방식에 따라 에러를 발생시킬 수 있으며, 다른 일부는 Rails 7.0을 위해 수정되어야 하는 deprecation 경고를 출력할 것입니다.

이 변경사항과 API 변경에 대한 자세한 내용은 이 PR에서 확인할 수 있습니다.

8 Rails 5.2에서 Rails 6.0으로 업그레이드

Rails 6.0에서 이루어진 변경사항에 대한 자세한 내용은 릴리스 노트를 참조하세요.

8.1 Webpacker 사용하기

Webpacker는 Rails 6의 기본 JavaScript 컴파일러입니다. 하지만 앱을 업그레이드하는 경우에는 기본적으로 활성화되어 있지 않습니다. Webpacker를 사용하고 싶다면, Gemfile에 포함시키고 설치하세요:

gem "webpacker"
$ bin/rails webpacker:install

8.2 Force SSL

Controller의 force_ssl 메서드는 deprecated 되었으며 Rails 6.1에서 제거될 예정입니다. 애플리케이션 전체에 HTTPS 연결을 적용하기 위해서는 config.force_ssl을 활성화하는 것을 권장합니다. 만약 특정 endpoint에서 리다이렉션을 제외해야 한다면, config.ssl_options를 사용하여 해당 동작을 설정할 수 있습니다.

8.3 보안 강화를 위해 signed와 encrypted 쿠키에 목적과 만료 메타데이터가 포함됨

보안 향상을 위해 Rails는 암호화되거나 서명된 쿠키 값 안에 목적과 만료 메타데이터를 포함시킵니다.

이를 통해 Rails는 쿠키의 signed/encrypted 값을 복사하여 다른 쿠키의 값으로 사용하려는 공격을 막을 수 있습니다.

이 새로운 포함된 메타데이터로 인해 Rails 6.0 이전 버전과는 호환되지 않습니다.

Rails 5.2 이하 버전에서 쿠키를 읽어야 하거나, 아직 6.0 배포를 검증 중이어서 롤백이 가능하도록 하려면 Rails.application.config.action_dispatch.use_cookies_with_metadatafalse로 설정하세요.

8.4 모든 npm 패키지가 @rails scope로 이동되었습니다

만약 이전에 npm/yarn을 통해 actioncable, activestorage, 또는 rails-ujs 패키지를 로드했다면, 이러한 의존성들을 6.0.0으로 업그레이드하기 전에 이름을 업데이트해야 합니다:

actioncable   → @rails/actioncable
activestorage → @rails/activestorage
rails-ujs     → @rails/ujs

8.5 Action Cable JavaScript API 변경사항

Action Cable JavaScript 패키지가 CoffeeScript에서 ES2015로 전환되었으며, 이제 npm 배포판에 소스 코드를 게시합니다.

이 릴리스에는 Action Cable JavaScript API의 선택적 부분에 대한 몇 가지 주요 변경사항이 포함되어 있습니다:

  • WebSocket 어댑터와 logger 어댑터의 설정이 ActionCable의 속성에서 ActionCable.adapters의 속성으로 이동되었습니다. 이러한 어댑터를 설정하는 경우 다음과 같은 변경이 필요합니다:

    -    ActionCable.WebSocket = MyWebSocket
    +    ActionCable.adapters.WebSocket = MyWebSocket
    
    -    ActionCable.logger = myLogger
    +    ActionCable.adapters.logger = myLogger
    
  • ActionCable.startDebugging()ActionCable.stopDebugging() 메서드가 제거되고 ActionCable.logger.enabled 속성으로 대체되었습니다. 이러한 메서드를 사용하고 있다면 다음과 같은 변경이 필요합니다:

    -    ActionCable.startDebugging()
    +    ActionCable.logger.enabled = true
    
    -    ActionCable.stopDebugging()
    +    ActionCable.logger.enabled = false
    

8.6 ActionDispatch::Response#content_type이 이제 Content-Type 헤더를 수정 없이 반환합니다

이전에는 ActionDispatch::Response#content_type의 반환값이 charset 부분을 포함하지 않았습니다. 이 동작이 이전에 생략되었던 charset 부분도 포함하도록 변경되었습니다.

MIME type만 필요한 경우 대신 ActionDispatch::Response#media_type을 사용하세요.

이전:

resp = ActionDispatch::Response.new(200, "Content-Type" => "text/csv; header=present; charset=utf-16")
resp.content_type #=> "text/csv; header=present"

죄송하지만 실수로 보내주신 번역할 원문이 없어서 번역을 해드릴 수 없네요. Rails 가이드 문서 내용을 공유해 주시면 번역해드리도록 하겠습니다.

resp = ActionDispatch::Response.new(200, "Content-Type" => "text/csv; header=present; charset=utf-16")
resp.content_type #=> "text/csv; header=present; charset=utf-16" 
resp.media_type   #=> "text/csv"

8.7 새로운 config.hosts 설정

이제 Rails는 보안 목적으로 새로운 config.hosts 설정을 가지고 있습니다. 이 설정은 development 환경에서 기본값으로 localhost로 되어 있습니다. development 환경에서 다른 도메인을 사용하는 경우 다음과 같이 허용해야 합니다:

# config/environments/development.rb

config.hosts << "dev.myapp.com"
config.hosts << /[a-z0-9-]+\.myapp\.com/ # 선택적으로 정규식도 사용할 수 있습니다

다른 환경의 경우 config.hosts는 기본적으로 비어있어 Rails가 host를 전혀 검증하지 않습니다. 필요한 경우 production 환경에서 검증하기 위해 선택적으로 추가할 수 있습니다.

8.8 Autoloading

Rails 6의 기본 설정

Rails 6.0에서 새로운 애플리케이션의 autoloader 설정은 다음과 같습니다:

# config/application.rb
config.load_defaults 6.0

이는 zeitwerk 모드를 활성화합니다:

# config/application.rb
config.autoloader = :zeitwerk

config/application.rb에서 config.load_defaults 6.0이 주석 처리되어 있거나 파일에서 제거된 경우, 기본값은 다음과 같이 classic 모드가 됩니다:

# config/application.rb
config.autoloader = :classic

레일스 팀은 classic 모드를 deprecated하는 것을 계획하고 있습니다. 새로운 애플리케이션은 zeitwerk 모드를 사용하는 것을 권장합니다.

# config/application.rb

config.load_defaults 6.0

이렇게 하면 해당 버전(이 경우 6.0)의 기본 설정이 활성화됩니다. 새로운 버전의 Rails로 업그레이드할 때는 새로운 기본값을 즉시 적용하지 않고도 애플리케이션을 수정할 수 있습니다.

CRuby에서 zeitwerk autoloading 모드를 활성화합니다. 이 모드에서는 autoloading, reloading, 그리고 eager loading이 Zeitwerk에 의해 관리됩니다.

이전 Rails 버전의 기본값을 사용하고 있다면, 다음과 같이 zeitwerk를 활성화할 수 있습니다:

# config/application.rb

config.autoloader = :zeitwerk

:zeitwerk를 autoloader로 사용하도록 애플리케이션을 구성합니다.

8.8.1 Public API

일반적으로, 애플리케이션은 Zeitwerk의 API를 직접 사용할 필요가 없습니다. Rails는 기존 규약에 따라 설정을 처리합니다: config.autoload_paths, config.cache_classes 등.

애플리케이션은 이 인터페이스를 따라야 하지만, 실제 Zeitwerk loader 객체는 다음과 같이 접근할 수 있습니다

Rails.autoloaders.main

예를 들어 Single Table Inheritance (STI) 클래스를 프리로드하거나 커스텀 inflector를 구성해야 하는 경우에 유용할 수 있습니다.

8.8.2 Project Structure

업그레이드되는 애플리케이션이 올바르게 autoload된다면, 프로젝트 구조는 이미 대부분 호환되어 있어야 합니다.

하지만 classic 모드는 누락된 상수 이름에서 파일 이름을 추론(underscore)하는 반면, zeitwerk 모드는 파일 이름에서 상수 이름을 추론(camelize)합니다. 이러한 헬퍼들은 특히 약어가 포함된 경우 항상 서로의 역연산이 되지는 않습니다. 예를 들어, "FOO".underscore"foo"이지만, "foo".camelize"FOO"가 아닌 "Foo"입니다.

호환성은 zeitwerk:check 태스크로 확인할 수 있습니다:

$ bin/rails zeitwerk:check
잠시만 기다려주세요, application을 eager loading 중입니다.
모두 정상입니다!

8.8.3 require_dependency

require_dependency의 모든 알려진 사용 사례들은 제거되었습니다. 프로젝트에서 이를 검색하여 삭제해야 합니다.

애플리케이션이 Single Table Inheritance를 사용하는 경우, Autoloading and Reloading Constants (Zeitwerk Mode) 가이드의 Single Table Inheritance 섹션을 참고하세요.

8.8.4 클래스와 모듈 정의에서의 정규화된 이름

이제 클래스와 모듈 정의에서 상수 경로를 안정적으로 사용할 수 있습니다:

# 이 클래스의 body 내의 Autoloading은 이제 Ruby 의미론과 일치합니다.
class Admin::UsersController < ApplicationController
  # ...
end

실행 순서에 따라, classic autoloader가 때때로 Foo::Wadus를 다음과 같이 autoload할 수 있다는 점을 주의해야 합니다.

class Foo::Bar
  Wadus
end

이는 Foo가 nesting에 없기 때문에 Ruby의 문법과 일치하지 않으며, zeitwerk 모드에서는 전혀 작동하지 않습니다. 이러한 특수한 경우를 발견하면 정규화된 이름 Foo::Wadus를 사용할 수 있습니다:

class Foo::Bar
  Foo::Wadus
end

또는 nesting에 Foo를 추가하세요:

module Foo
  class Bar
    Wadus
  end
end

8.8.5 Concerns

표준 구조에서 다음과 같이 autoload와 eager load를 할 수 있습니다:

app/models
app/models/concerns

이 디렉터리는 애플리케이션의 model들을 포함합니다. model은 비즈니스 로직을 포함하고 데이터베이스와의 상호작용을 담당합니다. model의 naming 및 작성 가이드라인에 대해서는 Rails Database Naming Conventions을 참조하세요. models/concerns는 여러 model 간에 공유되는 concern들을 포함합니다.

이 경우 app/models/concerns는 루트 디렉토리로 간주되며(autoload paths에 속하기 때문에) 네임스페이스로는 무시됩니다. 따라서 app/models/concerns/foo.rbConcerns::Foo가 아닌 Foo를 정의해야 합니다.

Concerns:: 네임스페이스는 classic autoloader에서 구현의 부작용으로 작동했지만, 이는 의도된 동작이 아니었습니다. Concerns::를 사용하는 애플리케이션은 zeitwerk 모드에서 실행하기 위해 해당 클래스와 모듈의 이름을 변경해야 합니다.

8.8.6 autoload paths에 app 포함하기

일부 프로젝트는 app/api/base.rbAPI::Base를 정의하기를 원하며, classic 모드에서 이를 달성하기 위해 app을 autoload paths에 추가합니다. Rails는 app의 모든 하위 디렉토리를 자동으로 autoload paths에 추가하기 때문에, 중첩된 루트 디렉토리가 있는 또 다른 상황이 발생하므로 이 설정은 더 이상 작동하지 않습니다. 위에서 concerns와 함께 설명한 것과 유사한 원칙입니다.

이러한 구조를 유지하고 싶다면, initializer에서 하위 디렉토리를 autoload paths에서 삭제해야 합니다:

ActiveSupport::Dependencies.autoload_paths에서 "#{Rails.root}/app/api" 삭제합니다

8.8.7 Autoloaded Constants와 명시적 Namespaces

namespace가 파일에서 정의되어 있다면, 여기서 Hotel처럼:

app/models/hotel.rb         # Hotel을 정의합니다.
app/models/hotel/pricing.rb # Hotel::Pricing을 정의합니다. 

Hotel 상수는 class 또는 module 키워드를 사용하여 설정해야 합니다. 예를 들면:

class Hotel
end

는 좋습니다.

다음과 같은 대안들이

Hotel = Class.new

또는

Hotel = Struct.new

작동하지 않을 것이며, Hotel::Pricing과 같은 자식 객체들을 찾을 수 없게 됩니다.

이 제한사항은 명시적인 namespace에만 적용됩니다. namespace를 정의하지 않는 클래스와 모듈은 이러한 방식을 사용하여 정의할 수 있습니다.

8.8.8 하나의 파일, 하나의 상수 (동일한 최상위 레벨에서)

classic 모드에서는 기술적으로 여러 상수를 동일한 최상위 레벨에서 정의하고 모두 리로드할 수 있었습니다. 예를 들어, 다음과 같은 경우:

# app/models/foo.rb

class Foo  
end

class Bar
end

Bar가 autoload되지 않은 상태에서 Foo를 autoload하면 Bar도 함께 autoload된 것으로 표시됩니다. 하지만 zeitwerk 모드에서는 그렇지 않으며, Barbar.rb라는 자체 파일로 옮겨야 합니다. 하나의 파일에는 하나의 상수만 정의되어야 합니다.

이는 위 예시처럼 같은 최상위 레벨에 있는 상수들에만 적용됩니다. 내부 클래스와 모듈은 괜찮습니다. 예를 들어 다음과 같은 경우를 살펴보겠습니다.

# app/models/foo.rb

class Foo
  class InnerClass
  end
end

애플리케이션이 Foo를 리로드하면, Foo::InnerClass도 함께 리로드됩니다.

8.8.9 Spring과 test 환경

Spring은 변경사항이 있을 때 애플리케이션 코드를 리로드합니다. test 환경에서는 이 기능이 동작하도록 리로딩을 활성화해야 합니다:

# config/environments/test.rb

config.cache_classes = false

이는 테스트 환경에서 클래스를 다시 로드할 수 있도록 설정하는 것입니다. 이렇게 하면 테스트 실행 간에 코드 변경 사항이 반영됩니다.

그렇지 않으면 다음과 같은 에러가 발생할 것입니다:

reloading이 비활성화되어 있습니다. config.cache_classes가 true이기 때문입니다

8.8.10 Bootsnap

Bootsnap은 최소 1.4.2 버전이어야 합니다.

추가로, Ruby 2.5를 실행할 때는 인터프리터의 버그로 인해 Bootsnap이 iseq 캐시를 비활성화해야 합니다. 이 경우 최소 Bootsnap 1.4.4 버전에 의존하도록 해주세요.

8.8.11 config.add_autoload_paths_to_load_path

새로운 설정 포인트인 config.add_autoload_paths_to_load_path는 하위 호환성을 위해 기본값이 true이지만, autoload 경로를 $LOAD_PATH에 추가하지 않도록 선택할 수 있습니다.

대부분의 애플리케이션에서 이는 합리적입니다. 예를 들어 app/models에 있는 파일을 절대 require할 필요가 없고, Zeitwerk는 내부적으로 절대 파일 경로만 사용하기 때문입니다.

이 옵션을 해제하면 $LOAD_PATH 조회를 최적화할 수 있고(확인할 디렉토리가 줄어듦), Bootsnap이 이 디렉토리들의 인덱스를 구축할 필요가 없어져서 작업량과 메모리 소비를 줄일 수 있습니다.

8.8.12 스레드 안정성

classic 모드에서 상수 autoloading은 스레드 안전하지 않습니다. 하지만 Rails는 개발 환경에서 일반적인 것처럼 autoloading이 활성화된 상태에서 웹 요청을 스레드 안전하게 만들기 위한 잠금 장치를 가지고 있습니다.

상수 autoloading은 zeitwerk 모드에서는 스레드 안전합니다. 예를 들어 이제 runner 명령으로 실행되는 멀티스레드 스크립트에서 autoload를 사용할 수 있습니다.

8.8.13 config.autoload_paths의 글로브

다음과 같은 설정을 주의하세요

config.autoload_paths += Dir["#{config.root}/lib/**/"]

lib 디렉터리와 하위의 모든 디렉터리를 autoload path에 추가합니다.

config.autoload_paths의 모든 요소는 최상위 namespace(Object)를 나타내야 하며, 결과적으로 중첩될 수 없습니다(위에서 설명한 concerns 디렉토리는 예외).

이를 해결하려면 와일드카드를 제거하면 됩니다:

config.autoload_paths << "#{config.root}/lib"

(이 라인은 /lib 디렉토리를 autoload path에 추가합니다)

8.8.14 Eager loading과 autoloading이 일관적입니다

classic 모드에서는 app/models/foo.rbBar를 정의하는 경우 해당 파일을 autoload할 수 없지만, eager loading은 파일들을 재귀적으로 무조건 로드하기 때문에 작동합니다. 만약 처음에 eager loading으로 테스트하면, 나중에 autoloading 시에는 실패할 수 있어서 이것이 오류의 원인이 될 수 있습니다.

zeitwerk 모드에서는 두 로딩 모드가 일관적이어서, 같은 파일에서 실패하고 오류가 발생합니다.

8.8.15 Rails 6에서 Classic Autoloader를 사용하는 방법

애플리케이션은 Rails 6 기본값을 로드하면서도 다음과 같이 config.autoloader를 설정하여 classic autoloader를 사용할 수 있습니다:

# config/application.rb

config.load_defaults 6.0
config.autoloader = :classic 

이 설정은 classic autoloader를 계속 사용하면서 Rails 6.0의 기본 설정을 로드합니다.

Rails 6 애플리케이션에서 Classic Autoloader를 사용할 때는 스레드 안전성 문제로 인해 development 환경의 web server와 background processor의 concurrency level을 1로 설정하는 것이 권장됩니다.

8.9 Active Storage 할당 동작 변경

Rails 5.2의 기본 구성에서는, has_many_attached로 선언된 첨부파일 컬렉션에 할당하면 새로운 파일들이 추가됩니다:

class User < ApplicationRecord
  has_many_attached :highlights
end

user.highlights.attach(filename: "funky.jpg") 
user.highlights.count # => 1

blob = ActiveStorage::Blob.create_after_upload!(filename: "town.jpg")
user.update!(highlights: [ blob ])

user.highlights.count # => 2
user.highlights.first.filename # => "funky.jpg"  
user.highlights.second.filename # => "town.jpg"

Rails 6.0의 기본 설정에서는, attachment 컬렉션에 할당할 때 파일을 추가하는 대신 기존 파일을 대체합니다. 이는 컬렉션 association에 할당할 때의 Active Record 동작과 일치합니다:

user.highlights.attach(filename: "funky.jpg") 
user.highlights.count # => 1

blob = ActiveStorage::Blob.create_after_upload!(filename: "town.jpg")
user.update!(highlights: [ blob ])

user.highlights.count # => 1
user.highlights.first.filename # => "town.jpg"

#attach는 기존의 attachment들을 제거하지 않고 새로운 attachment를 추가하는데 사용할 수 있습니다:

blob = ActiveStorage::Blob.create_after_upload!(filename: "town.jpg")
user.highlights.attach(blob)

user.highlights.count # => 2
user.highlights.first.filename # => "funky.jpg" 
user.highlights.second.filename # => "town.jpg"

기존 애플리케이션은 config.active_storage.replace_on_assign_to_manytrue로 설정하여 이 새로운 동작을 선택할 수 있습니다. 이전 동작은 Rails 7.0에서 deprecated 될 예정이며 Rails 7.1에서 제거될 예정입니다.

8.10 커스텀 예외 처리 애플리케이션

유효하지 않은 Accept 또는 Content-Type 요청 헤더는 이제 예외를 발생시킵니다. 기본 config.exceptions_app은 해당 오류를 특별히 처리하고 이를 보완합니다. 커스텀 예외 애플리케이션도 해당 오류를 처리해야 합니다. 그렇지 않으면 이러한 요청들이 Rails로 하여금 대체 예외 애플리케이션을 사용하게 하여 500 Internal Server Error를 반환하게 됩니다.

9 Rails 5.1에서 Rails 5.2로 업그레이드하기

Rails 5.2에서 이루어진 변경사항에 대한 자세한 내용은 릴리스 노트를 참조하세요.

9.1 Bootsnap

Rails 5.2는 새로 생성된 앱의 Gemfile에 bootsnap gem을 추가합니다. app:update 명령어는 boot.rb에서 이를 설정합니다. 이를 사용하려면 Gemfile에 추가하세요:

# 캐싱을 통해 부팅 시간을 단축시킵니다; config/boot.rb에서 필요함
gem "bootsnap", require: false

bootsnap을 사용하지 않으려면 boot.rb를 변경하세요.

9.2 서명되거나 암호화된 쿠키의 만료 정보가 이제 쿠키 값에 포함됨

보안 향상을 위해 Rails는 이제 만료 정보를 암호화되거나 서명된 쿠키 값에도 포함시킵니다.

이 새로운 포함된 정보로 인해 해당 쿠키들은 Rails 5.2 이전 버전과 호환되지 않습니다.

만약 쿠키가 5.1 이하 버전에서도 읽혀야 하거나, 아직 5.2 배포를 검증 중이어서 롤백이 가능하도록 하고 싶다면 Rails.application.config.action_dispatch.use_authenticated_cookie_encryptionfalse로 설정하세요.

10 Rails 5.0에서 Rails 5.1로 업그레이드

Rails 5.1의 변경사항에 대한 자세한 내용은 릴리스 노트를 참조하세요.

10.1 최상위 HashWithIndifferentAccess는 소프트 deprecated 되었습니다

애플리케이션에서 최상위 HashWithIndifferentAccess 클래스를 사용하고 있다면, ActiveSupport::HashWithIndifferentAccess를 대신 사용하도록 코드를 점진적으로 변경해야 합니다.

이것은 소프트 deprecated일 뿐이므로, 현재 코드가 깨지거나 deprecation 경고가 표시되지는 않지만, 이 상수는 향후 제거될 예정입니다.

또한, 이러한 객체들의 dump를 포함하는 오래된 YAML 문서가 있다면, 올바른 상수를 참조하도록 하고 향후 로드할 때 문제가 발생하지 않도록 하기 위해 다시 로드하고 dump할 필요가 있을 수 있습니다.

10.2 application.secrets가 이제 모든 키를 symbol로 로드합니다

애플리케이션이 config/secrets.yml에 중첩된 설정을 저장하는 경우, 이제 모든 키가 symbol로 로드되므로 string을 사용하는 접근 방식을 변경해야 합니다.

변경 전:

Rails.application.secrets[:smtp_settings]["address"]

번역 할 내용이 제공되지 않았습니다. Rails 가이드 문서의 내용을 주시면 번역해드리도록 하겠습니다.

Rails.application.secrets[:smtp_settings][:address]

10.3 render에서 더 이상 사용되지 않는 :text:nothing 지원 제거

컨트롤러에서 render :text를 사용하고 있다면 더 이상 작동하지 않습니다. MIME type이 text/plain인 텍스트를 렌더링하는 새로운 방법은 render :plain을 사용하는 것입니다.

마찬가지로, render :nothing도 제거되었으며 헤더만 포함된 응답을 보내려면 head 메서드를 사용해야 합니다. 예를 들어, head :ok는 본문 없이 200 응답을 보냅니다.

10.4 redirect_to :back 지원 중단

Rails 5.0에서 redirect_to :back은 deprecated 되었습니다. Rails 5.1에서는 완전히 제거되었습니다.

대안으로 redirect_back을 사용하세요. redirect_backHTTP_REFERER가 없는 경우 사용될 fallback_location 옵션도 함께 사용해야 한다는 점에 주의하세요.

redirect_back(fallback_location: root_path)

request가 있었던 이전 페이지로 돌아가고, 만약 HTTP_REFERER이 없다면 fallback_location으로 redirect 합니다.

11 Upgrading from Rails 4.2 to Rails 5.0

Rails 5.0에서 변경된 사항에 대한 자세한 내용은 release notes를 참조하세요.

11.1 Ruby 2.2.2+ 필수

Ruby on Rails 5.0부터는 Ruby 2.2.2+ 버전만 지원됩니다. 계속 진행하기 전에 Ruby 2.2.2 이상의 버전을 사용하고 있는지 확인하세요.

11.2 Active Record Models는 이제 기본적으로 ApplicationRecord를 상속합니다

Rails 4.2에서는 Active Record model이 ActiveRecord::Base를 상속했습니다. Rails 5.0에서는 모든 model이 ApplicationRecord를 상속합니다.

ApplicationRecord는 모든 앱 model을 위한 새로운 superclass입니다. 이는 app controller가 ActionController::Base 대신 ApplicationController를 상속하는 것과 유사합니다. 이를 통해 앱은 앱 전체의 model 동작을 설정할 수 있는 단일 지점을 갖게 됩니다.

Rails 4.2에서 Rails 5.0으로 업그레이드할 때는 app/models/ 디렉토리에 application_record.rb 파일을 생성하고 다음 내용을 추가해야 합니다:

class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
end

이것은 Rails 5.0에서 도입된 새로운 클래스입니다. 모든 model이 상속하는 추상 클래스입니다. 이것은 직접적으로 생성되지 않으며 대신 템플릿 역할을 하는 클래스입니다. ActiveRecord::Base와는 달리, ApplicationRecord는 자유롭게 코드를 수정할 수 있습니다. 예를 들어 전체 애플리케이션에 대해 특정 scope나 메서드를 정의할 수 있습니다.

그리고 모든 model들이 이것을 상속받는지 확인하세요.

11.3 throw(:abort)를 통한 Callback Chain 중단하기

Rails 4.2에서는 Active Record와 Active Model의 'before' callback이 false를 반환하면 전체 callback chain이 중단됩니다. 다시 말해서, 이후의 'before' callback들은 실행되지 않으며, callback으로 감싸진 액션도 실행되지 않습니다.

Rails 5.0에서는 Active Record나 Active Model callback에서 false를 반환하더라도 callback chain을 중단하는 부수 효과가 없습니다. 대신, callback chain을 명시적으로 중단하려면 throw(:abort)를 호출해야 합니다.

Rails 4.2에서 Rails 5.0으로 업그레이드할 때, 이러한 종류의 callback에서 false를 반환하면 여전히 callback chain이 중단되지만, 이 예정된 변경사항에 대한 deprecation 경고를 받게 됩니다.

준비가 되었다면, config/application.rb에 다음 설정을 추가하여 새로운 동작을 적용하고 deprecation 경고를 제거할 수 있습니다:

ActiveSupport.halt_callback_chains_on_return_false = false

Active Support 콜백의 경우 어떤 값이 반환되더라도 체인을 중단하지 않기 때문에 이 옵션은 영향을 미치지 않는다는 점에 유의하세요.

자세한 내용은 #17227을 참조하세요.

11.4 ActiveJob는 이제 기본적으로 ApplicationJob을 상속받습니다

Rails 4.2에서는 Active Job가 ActiveJob::Base를 상속받았습니다. Rails 5.0에서는 이 동작이 ApplicationJob을 상속받도록 변경되었습니다.

Rails 4.2에서 Rails 5.0으로 업그레이드할 때, app/jobs/ 디렉토리에 application_job.rb 파일을 생성하고 다음 내용을 추가해야 합니다:

class ApplicationJob < ActiveJob::Base 
end

참고: 이 파일은 새로운 Rails 애플리케이션에서 생성되는 기본 파일입니다. 모든 Job은 이 클래스를 상속받아야 합니다.

그런 다음 모든 job 클래스가 이를 상속하는지 확인하세요.

자세한 내용은 #19034를 참조하세요.

11.5 Rails Controller Testing

11.5.1 rails-controller-testing로의 일부 헬퍼 메소드 추출

assignsassert_templaterails-controller-testing gem으로 추출되었습니다. controller 테스트에서 이 메소드들을 계속 사용하려면 Gemfilegem "rails-controller-testing"를 추가하세요.

RSpec을 테스트에 사용하고 있다면, gem의 문서에서 필요한 추가 설정을 확인하시기 바랍니다.

11.5.2 파일 업로드시 새로운 동작

테스트에서 파일 업로드를 위해 ActionDispatch::Http::UploadedFile을 사용하고 있다면, 대신 비슷한 Rack::Test::UploadedFile 클래스를 사용하도록 변경해야 합니다.

자세한 내용은 #26404를 참조하세요.

11.6 Production 환경에서 부팅 후 Autoloading이 비활성화됨

Production 환경에서는 기본적으로 부팅 후 autoloading이 비활성화됩니다.

애플리케이션의 eager loading은 부팅 프로세스의 일부이므로, 최상위 상수들은 문제없이 계속 autoload되며 이들의 파일을 require할 필요가 없습니다.

일반 메서드 본문과 같이 런타임에만 실행되는 더 깊은 위치에 있는 상수들도 문제없습니다. 이는 부팅하는 동안 해당 상수를 정의하는 파일이 이미 eager load되었기 때문입니다.

대부분의 애플리케이션에서 이 변경사항은 아무런 조치가 필요하지 않습니다. 하지만 매우 드물게 production 환경에서 실행 중에 autoloading이 필요한 경우, Rails.application.config.enable_dependency_loading을 true로 설정하세요.

11.7 XML Serialization

ActiveModel::Serializers::Xml은 Rails에서 activemodel-serializers-xml gem으로 분리되었습니다. 어플리케이션에서 XML serialization을 계속 사용하려면 Gemfilegem "activemodel-serializers-xml"을 추가하세요.

11.8 Legacy mysql 데이터베이스 어댑터 지원 제거

Rails 5에서는 legacy mysql 데이터베이스 어댑터에 대한 지원이 제거되었습니다. 대부분의 사용자는 대신 mysql2를 사용할 수 있습니다. 이는 유지보수할 담당자를 찾으면 별도의 gem으로 전환될 예정입니다.

11.9 Debugger 지원 제거

Rails 5에서 필요로 하는 Ruby 2.2는 debugger를 지원하지 않습니다. 대신 byebug를 사용하세요.

11.10 bin/rails를 사용하여 task와 test 실행하기

Rails 5에서는 rake 대신 bin/rails를 통해 task와 test를 실행할 수 있는 기능이 추가되었습니다. 일반적으로 이러한 변경사항들은 rake와 병행되지만, 일부는 완전히 이전되었습니다.

새로운 test runner를 사용하려면 간단히 bin/rails test를 입력하세요.

rake dev:cache는 이제 bin/rails dev:cache가 되었습니다.

사용 가능한 명령어 목록을 보려면 애플리케이션의 루트 디렉토리에서 bin/rails를 실행하세요.

11.11 ActionController::Parameters는 더 이상 HashWithIndifferentAccess를 상속하지 않음

애플리케이션에서 params를 호출하면 이제 hash 대신 객체를 반환합니다. 매개변수가 이미 permitted(허용)된 상태라면 어떠한 변경도 할 필요가 없습니다. 만약 permitted? 상태와 관계없이 hash를 읽을 수 있어야 하는 map과 같은 메서드를 사용하고 있다면, 먼저 permit(허용)하고 hash로 변환하도록 애플리케이션을 업그레이드해야 합니다.

params.permit([:proceed_to, :return_to]).to_h

11.12 protect_from_forgery는 이제 기본값이 prepend: false입니다

protect_from_forgery는 이제 prepend: false가 기본값이며, 이는 애플리케이션에서 호출하는 시점에 callback chain에 삽입된다는 것을 의미합니다. 만약 protect_from_forgery가 항상 먼저 실행되기를 원한다면, 애플리케이션에서 protect_from_forgery prepend: true를 사용하도록 변경해야 합니다.

11.13 Default Template Handler가 이제 RAW입니다

확장자에 template handler가 없는 파일들은 raw handler를 사용해 렌더링됩니다. 이전에는 Rails가 ERB template handler를 사용해 파일을 렌더링했습니다.

파일을 raw handler로 처리하고 싶지 않다면, 적절한 template handler로 파싱될 수 있는 확장자를 파일에 추가해야 합니다.

11.14 Template Dependencies에 대한 와일드카드 매칭 추가

이제 template dependencies에 대해 와일드카드 매칭을 사용할 수 있습니다. 예를 들어, 템플릿을 다음과 같이 정의했다면:

<% # Template 의존성: recordings/threads/events/subscribers_changed %>
<% # Template 의존성: recordings/threads/events/completed %>
<% # Template 의존성: recordings/threads/events/uncompleted %>

이제 와일드카드를 사용하여 dependency를 한 번만 호출할 수 있습니다.

<% # Template Dependency: recordings/threads/events/* %>

11.15 ActionView::Helpers::RecordTagHelper가 외부 gem(record_tag_helper)으로 이동됨

content_tag_fordiv_forcontent_tag만 사용하도록 제거되었습니다. 이전 메소드들을 계속 사용하려면 Gemfilerecord_tag_helper gem을 추가하세요:

gem "record_tag_helper", "~> 1.0"

자세한 내용은 #18411을 참조하세요.

11.16 protected_attributes Gem 지원 제거

Rails 5에서는 더 이상 protected_attributes gem을 지원하지 않습니다.

11.17 activerecord-deprecated_finders gem에 대한 지원 종료

activerecord-deprecated_finders gem은 더 이상 Rails 5에서 지원되지 않습니다.

11.18 ActiveSupport::TestCase의 기본 테스트 순서가 이제 임의 순서로 변경됨

애플리케이션에서 테스트가 실행될 때, 기본 순서가 :sorted에서 :random으로 변경되었습니다. 다음 config 옵션을 사용하여 :sorted로 되돌릴 수 있습니다.

# config/environments/test.rb
Rails.application.configure do
  config.active_support.test_order = :sorted
end

11.19 ActionController::LiveConcern이 되었습니다

ActionController::Live를 컨트롤러에 포함된 다른 모듈에 포함시킬 경우, 해당 모듈에 ActiveSupport::Concern도 함께 extend해야 합니다. 또는 StreamingSupport가 포함된 후에 컨트롤러에 직접 ActionController::Live를 포함시키기 위해 self.included hook을 사용할 수 있습니다.

이는 애플리케이션이 자체 streaming 모듈을 사용하고 있었다면, 다음과 같은 코드가 production 환경에서 동작하지 않을 수 있다는 것을 의미합니다:

# 이것은 Warden/Devise를 사용한 인증을 수행하는 streamed 컨트롤러를 위한 해결 방법입니다.
# https://github.com/plataformatec/devise/issues/2332 참조
# 해당 이슈에서 제안된 대로 라우터에서 인증하는 것이 또 다른 해결책입니다
class StreamingSupport
  include ActionController::Live # Rails 5의 production 환경에서는 작동하지 않습니다
  # extend ActiveSupport::Concern # 이 줄의 주석을 해제하지 않는 한

  def process(name)
    super(name)
  rescue ArgumentError => e
    if e.message == "uncaught throw :warden"
      throw :warden
    else
      raise e
    end
  end
end

11.20 새로운 프레임워크 기본값

11.20.1 Active Record belongs_to의 기본 필수 옵션

이제 belongs_to는 기본적으로 association이 없는 경우 validation 오류를 발생시킵니다.

이는 association 별로 optional: true를 사용하여 비활성화할 수 있습니다.

이 기본값은 새로운 애플리케이션에서 자동으로 설정됩니다. 기존 애플리케이션에서 이 기능을 추가하려면 initializer에서 활성화해야 합니다:

config.active_record.belongs_to_required_by_default = true

belongs_to 관계에서 belongs_to 연관이 유효하기 위해서는 연관된 레코드가 반드시 존재해야 합니다. belongs_to 관계를 선언할 때 optional: true를 지정하여 이 기본 동작을 비활성화할 수 있습니다.

설정은 기본적으로 모든 모델에 대해 전역적으로 적용되지만, 모델별로 재정의할 수 있습니다. 이를 통해 모든 모델의 association이 기본적으로 필수가 되도록 마이그레이션하는 데 도움이 될 것입니다.

class Book < ApplicationRecord
  # model이 아직 기본적으로 association을 필수로 요구할 준비가 되지 않음

  self.belongs_to_required_by_default = false
  belongs_to(:author)
end

class Car < ApplicationRecord
  # model이 기본적으로 association을 필수로 요구할 준비가 됨

  self.belongs_to_required_by_default = true
  belongs_to(:pilot)
end

11.20.2 Form별 CSRF 토큰

Rails 5는 JavaScript로 생성된 form에서의 코드 주입 공격을 완화하기 위해 form별 CSRF 토큰을 지원합니다. 이 옵션을 활성화하면 애플리케이션의 form들은 각각 해당 form의 action과 method에 특화된 고유한 CSRF 토큰을 가지게 됩니다.

이 옵션은 각 폼마다 특정한 CSRF 토큰을 생성하도록 합니다. 이는 form 앨리먼트의 action 속성과 method를 CSRF 토큰에 바인딩합니다. 이렇게 하면 제출된 폼이 원래 의도된 목적과 다른 엔드포인트로 재전송되는 것을 방지합니다.

11.20.3 Origin 체크를 통한 위조 방지

이제 CSRF 방어의 추가 수단으로 HTTP Origin 헤더를 사이트의 origin과 대조하여 확인하도록 애플리케이션을 설정할 수 있습니다. 설정 파일에서 다음을 true로 설정하세요:

Rails는 Cross-Origin Request Forgery 보호 기능을 사용할 때, 동일 출처(same origin)에서만 요청을 허용합니다. HTTP Origin 헤더가 있는 경우, Rails는 이 헤더가 요청의 호스트 헤더와 일치하는지 검증합니다. 이 기능은 config.action_controller.forgery_protection_origin_check = true로 활성화됩니다.

11.20.4 Action Mailer Queue Name 구성 허용

기본 mailer queue 이름은 mailers입니다. 이 구성 옵션을 사용하면 queue 이름을 전역적으로 변경할 수 있습니다. 구성에서 다음을 설정하세요:

config.action_mailer.deliver_later_queue_name = :new_queue_name

Action Mailer에서 deliver_later를 사용할 때 어떤 queue를 사용할지 지정합니다.

11.20.5 Action Mailer 뷰에서 Fragment Caching 지원

설정에서 config.action_mailer.perform_caching을 설정하여 Action Mailer 뷰가 caching을 지원할지 여부를 결정할 수 있습니다.

config.action_mailer.perform_caching = true

Action Mailer가 fragment caching을 수행할지 여부를 지정합니다.

11.20.6 db:structure:dump의 출력 설정

schema_search_path 또는 다른 PostgreSQL 확장 기능을 사용하는 경우, 스키마가 덤프되는 방식을 제어할 수 있습니다. 모든 덤프를 생성하려면 :all로 설정하고, schema search path에서 생성하려면 :schema_search_path로 설정하세요.

config.active_record.dump_schemas = :all

모든 데이터베이스의 스키마를 덤프합니다. 기본값은 :schema_search_path입니다. main 데이터베이스가 아닌 다른 스키마(schema)나 데이터베이스가 있는 경우 :all로 설정해주세요.

11.20.7 서브도메인과 함께 HSTS를 활성화하기 위한 SSL 옵션 구성

서브도메인을 사용할 때 HSTS를 활성화하려면 config에 다음과 같이 설정하세요:

config.ssl_options = { hsts: { subdomains: true } }

11.20.8 수신자의 타임존 보존

Ruby 2.4를 사용할 때, to_time을 호출할 때 수신자의 타임존을 보존할 수 있습니다.

ActiveSupport.to_time_preserves_timezone = false

11.21 JSON/JSONB 직렬화 변경사항

Rails 5.0에서는 JSON/JSONB 속성의 직렬화 및 역직렬화 방식이 변경되었습니다. 이제 컬럼을 String으로 설정하면 Active Record는 더 이상 그 문자열을 Hash로 변환하지 않고 문자열 그대로 반환합니다. 이는 모델과 상호작용하는 코드에만 국한되지 않고 db/schema.rb:default 컬럼 설정에도 영향을 미칩니다. 컬럼을 String으로 설정하는 대신, 자동으로 JSON 문자열로 변환되는 Hash를 전달하는 것이 권장됩니다.

12 Rails 4.1에서 Rails 4.2로 업그레이드

12.1 Web Console

먼저 Gemfile:development 그룹에 gem "web-console", "~> 2.0"를 추가하고 bundle install을 실행하세요(Rails를 업그레이드했을 때 포함되지 않았을 것입니다). 설치가 완료되면, console helper(즉, <%= console %>)를 활성화하고 싶은 view에 간단히 추가하면 됩니다. 개발 환경에서 보는 모든 에러 페이지에도 console이 제공됩니다.

12.2 Responders

respond_with와 클래스 레벨의 respond_to 메소드들은 responders gem으로 분리되었습니다. 이를 사용하기 위해서는 단순히 Gemfilegem "responders", "~> 2.0"를 추가하면 됩니다. responders gem을 의존성에 포함시키지 않으면 respond_withrespond_to(다시 말하지만, 클래스 레벨에서)에 대한 호출이 더 이상 작동하지 않을 것입니다:

# app/controllers/users_controller.rb

class UsersController < ApplicationController
  respond_to :html, :json

  def show
    @user = User.find(params[:id])
    respond_with @user
  end
end

인스턴스 레벨의 respond_to는 영향을 받지 않으며 추가 gem이 필요하지 않습니다:

# app/controllers/users_controller.rb

class UsersController < ApplicationController
  def show
    @user = User.find(params[:id])
    respond_to do |format|
      format.html
      format.json { render json: @user }
    end
  end
end

자세한 내용은 #16526을 참조하세요.

12.3 트랜잭션 콜백에서의 에러 처리

현재 Active Record는 after_rollback 또는 after_commit 콜백 내에서 발생하는 에러를 억제하고 로그에만 출력합니다. 다음 버전에서는 이러한 에러들이 더 이상 억제되지 않을 것입니다. 대신, 다른 Active Record 콜백들처럼 에러가 정상적으로 전파될 것입니다.

after_rollback 또는 after_commit 콜백을 정의할 때, 이 예정된 변경사항에 대한 deprecation 경고를 받게 될 것입니다. 준비가 되었다면, config/application.rb에 다음 설정을 추가하여 새로운 동작을 적용하고 deprecation 경고를 제거할 수 있습니다:

config.active_record.raise_in_transactional_callbacks = true

#14488#16537에서 자세한 내용을 확인하세요.

12.4 Test case의 순서

Rails 5.0에서는 test case가 기본적으로 무작위 순서로 실행됩니다. 이러한 변화에 대비하여 Rails 4.2에서는 test 순서를 명시적으로 지정할 수 있는 새로운 configuration option인 active_support.test_order를 도입했습니다. 이를 통해 :sorted로 설정하여 현재 동작을 고정하거나, :random으로 설정하여 미래의 동작을 선택할 수 있습니다.

이 option에 대한 값을 지정하지 않으면 deprecation warning이 발생합니다. 이를 방지하려면 test 환경에 다음 줄을 추가하세요:

# config/environments/test.rb
Rails.application.configure do
  config.active_support.test_order = :sorted # 또는 선호하시는 대로 `:random`을 사용하세요
end

12.5 Serialized attributes

커스텀 coder를 사용할 때(예: serialize :metadata, JSON), serialized attribute에 nil을 할당하면 coder를 통과시키는 대신(예: JSON coder를 사용할 때의 "null") 데이터베이스에 NULL로 저장됩니다.

12.6 Production log level

Rails 5에서는 production 환경의 기본 log level이 (:info에서) :debug로 변경됩니다. 현재의 기본값을 유지하려면 production.rb에 다음 라인을 추가하세요:

# 현재 기본값과 일치하도록 `:info`로 설정하거나, 
# 향후 기본값을 적용하려면 `:debug`로 설정하세요.
config.log_level = :info

12.7 Rails 템플릿의 after_bundle

만약 모든 파일을 버전 컨트롤에 추가하는 Rails 템플릿이 있다면, Bundler가 실행되기 전에 실행되므로 생성된 binstub들을 추가하는데 실패합니다.

# template.rb
generate(:scaffold, "person name:string")
route "root to: 'people#index'"
rake("db:migrate")

git :init
git add: "."
git commit: %Q{ -m '최초 커밋' }

git 호출을 after_bundle 블록으로 감쌀 수 있습니다. 이는 binstub들이 생성된 후에 실행됩니다.

# template.rb
generate(:scaffold, "person name:string")
route "root to: 'people#index'"
rake("db:migrate")

after_bundle do
  git :init
  git add: "."
  git commit: %Q{ -m '최초 커밋' }
end

12.8 Rails HTML Sanitizer

애플리케이션에서 HTML 조각을 sanitize하는 새로운 방법이 있습니다. 기존의 html-scanner 방식은 이제 공식적으로 Rails HTML Sanitizer를 선호하는 방향으로 deprecated 되었습니다.

이는 sanitize, sanitize_css, strip_tags, strip_links 메서드들이 새로운 구현으로 지원된다는 것을 의미합니다.

이 새로운 sanitizer는 내부적으로 Loofah를 사용합니다. Loofah는 Nokogiri를 사용하는데, 이는 C와 Java로 작성된 XML parser들을 래핑하고 있어서 어떤 Ruby 버전을 실행하더라도 sanitization이 더 빠를 것입니다.

새 버전은 sanitize를 업데이트하여 강력한 scrubbing을 위해 Loofah::Scrubber를 사용할 수 있게 되었습니다. 여기에서 scrubber의 예시를 확인하세요.

두 개의 새로운 scrubber도 추가되었습니다: PermitScrubberTargetScrubber입니다. 더 자세한 정보는 gem의 readme를 읽어보세요.

PermitScrubberTargetScrubber의 문서는 요소를 언제 어떻게 제거할지에 대해 완전한 제어를 할 수 있는 방법을 설명합니다.

만약 애플리케이션에서 이전 sanitizer 구현을 사용해야 한다면, Gemfilerails-deprecated_sanitizer를 포함하세요:

gem "rails-deprecated_sanitizer"

12.9 Rails DOM Testing

TagAssertions 모듈(assert_tag와 같은 메서드를 포함)은 SelectorAssertions 모듈의 assert_select 메서드를 위해 deprecated 되었으며, 이는 rails-dom-testing gem으로 추출되었습니다.

12.10 Masked Authenticity Tokens

SSL 공격을 완화하기 위해, form_authenticity_token은 이제 각 요청마다 다르게 마스킹됩니다. 따라서 토큰은 마스킹을 해제한 다음 복호화하여 검증됩니다. 결과적으로, 정적 세션 CSRF 토큰에 의존하는 non-rails form의 요청을 검증하는 모든 전략들은 이를 고려해야 합니다.

12.11 Action Mailer

이전에는 mailer 클래스에서 mailer 메서드를 호출하면 해당 인스턴스 메서드가 직접 실행되었습니다. Active Job과 #deliver_later가 도입되면서 이는 더 이상 사실이 아닙니다. Rails 4.2에서는 deliver_now 또는 deliver_later가 호출될 때까지 인스턴스 메서드의 실행이 지연됩니다. 예를 들어:

class Notifier < ActionMailer::Base
  def notify(user)
    puts "호출됨"
    mail(to: user.email) 
  end
end
mail = Notifier.notify(user) # 이 시점에서는 아직 Notifier#notify가 호출되지 않음
mail = mail.deliver_now           # "Called" 출력

대부분의 애플리케이션에서는 눈에 띄는 차이가 발생하지 않을 것입니다. 하지만 일부 non-mailer 메서드를 동기적으로 실행해야 하고, 이전에 동기적 프록시 동작에 의존하고 있었다면, mailer 클래스에서 직접 클래스 메서드로 정의해야 합니다:

class Notifier < ActionMailer::Base
  def self.broadcast_notifications(users, ...)
    users.each { |user| Notifier.notify(user, ...) }
  end
end

위의 코드는 모든 users에 대해 notify를 호출합니다.

12.12 Foreign Key 지원

Migration DSL이 foreign key 정의를 지원하도록 확장되었습니다. Foreigner gem을 사용하고 계셨다면 이를 제거하는 것을 고려해보세요. Rails의 foreign key 지원은 Foreigner의 부분집합이라는 점을 주의하세요. 이는 모든 Foreigner 정의를 Rails migration DSL로 완벽하게 대체할 수는 없다는 것을 의미합니다.

마이그레이션 절차는 다음과 같습니다:

  1. Gemfile에서 gem "foreigner"를 제거합니다.
  2. bundle install을 실행합니다.
  3. bin/rake db:schema:dump를 실행합니다.
  4. db/schema.rb가 필요한 옵션과 함께 모든 foreign key 정의를 포함하고 있는지 확인합니다.

13 Upgrading from Rails 4.0 to Rails 4.1

13.1 원격 <script> 태그로부터의 CSRF 보호

또는, "으악 내 테스트가 실패하고 있어!!!" 또는 "내 <script> 위젯이 망가졌어!!"

Cross-site request forgery (CSRF) 보호가 이제 JavaScript 응답이 있는 GET 요청도 포함합니다. 이는 제3자 사이트가 <script> 태그를 사용하여 민감한 데이터를 추출하기 위해 당신의 JavaScript를 원격으로 참조하는 것을 방지합니다.

이는 다음을 사용하는 기능 테스트와 통합 테스트가

get :index, format: :js

CSRF protection이 이제 트리거됩니다. 다음으로 전환하세요

xhr :get, :index, format: :js

XmlHttpRequest를 명시적으로 테스트하기 위해서입니다.

자체적인 <script> 태그도 교차 출처로 간주되어 기본적으로 차단됩니다. 만약 <script> 태그로부터 JavaScript를 로드하려면, 이제 해당 액션들에 대해 명시적으로 CSRF 보호를 스킵해야 합니다.

13.2 Spring

애플리케이션 preloader로 Spring을 사용하려면 다음과 같이 해야 합니다:

  1. Gemfilegem "spring", group: :development를 추가하세요.
  2. bundle install을 사용하여 spring을 설치하세요.
  3. bundle exec spring binstub으로 Spring binstub을 생성하세요.

사용자가 정의한 rake 작업은 기본적으로 development 환경에서 실행됩니다. 다른 환경에서 실행하려면 Spring README를 참고하세요.

13.3 config/secrets.yml

애플리케이션의 secrets를 저장하기 위해 새로운 secrets.yml 규칙을 사용하고 싶다면 다음과 같이 해야 합니다:

  1. config 폴더에 다음 내용으로 secrets.yml 파일을 생성하세요:

    development:
      secret_key_base:
    
    test:
      secret_key_base:
    
    production:
      secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
    
  2. production 환경에서 Rails 애플리케이션을 실행하는 사용자들을 위해 secret_token.rb initializer에서 기존의 secret_key_base를 사용하여 SECRET_KEY_BASE 환경 변수를 설정하세요. 또는 secret_token.rb initializer에서 기존 secret_key_basesecrets.ymlproduction 섹션에 <%= ENV["SECRET_KEY_BASE"] %>를 대체하여 복사할 수도 있습니다.

  3. secret_token.rb initializer를 제거하세요.

  4. rake secret을 사용하여 developmenttest 섹션을 위한 새로운 키를 생성하세요.

  5. 서버를 재시작하세요.

13.4 test helper 변경사항

만약 test helper에 ActiveRecord::Migration.check_pending! 호출이 포함되어 있다면 이를 제거할 수 있습니다. 이 검사는 이제 require "rails/test_help"를 실행할 때 자동으로 수행되지만, helper에 이 라인을 남겨두어도 아무런 문제가 되지 않습니다.

13.5 Cookies serializer

Rails 4.1 이전에 생성된 애플리케이션들은 signed 및 encrypted cookie jar에 cookie 값을 직렬화하기 위해 Marshal을 사용합니다. 애플리케이션에서 새로운 JSON 기반 형식을 사용하고 싶다면, 다음 내용으로 initializer 파일을 추가할 수 있습니다:

Rails.application.config.action_dispatch.cookies_serializer = :hybrid

:hybrid serializer를 사용하면 기존의 Marshal로 직렬화된 cookie를 읽어들일 수 있지만, 새로 작성되는 cookie는 JSON 형식으로 직렬화됩니다.

이는 기존의 Marshal로 직렬화된 쿠키를 새로운 JSON 기반 형식으로 투명하게 마이그레이션합니다.

:json 또는 :hybrid 시리얼라이저를 사용할 때는 모든 Ruby 객체가 JSON으로 직렬화될 수 있는 것은 아니라는 점에 주의해야 합니다. 예를 들어, DateTime 객체는 문자열로 직렬화되며, Hash의 키는 문자열화됩니다.

class CookiesController < ApplicationController
  def set_cookie
    cookies.encrypted[:expiration_date] = Date.tomorrow # => 목, 20 3월 2014
    redirect_to action: "read_cookie" 
  end

  def read_cookie
    cookies.encrypted[:expiration_date] # => "2014-03-20"
  end
end

쿠키에는 단순한 데이터(문자열과 숫자)만 저장하는 것이 좋습니다. 복잡한 객체를 저장해야 하는 경우, 후속 요청에서 값을 읽을 때 수동으로 변환을 처리해야 합니다.

쿠키 세션 저장소를 사용하는 경우, 이는 sessionflash 해시에도 적용됩니다.

13.6 Flash 구조 변경

Flash 메시지 키가 문자열로 정규화 되었습니다. 여전히 심볼이나 문자열을 사용해서 접근할 수 있습니다. Flash를 반복할 때는 항상 문자열 키가 반환됩니다:

flash["string"] = "a string"
flash[:symbol] = "a symbol"

# Rails < 4.1 
flash.keys # => ["string", :symbol]

# Rails >= 4.1
flash.keys # => ["string", "symbol"] 

Flash message key들을 문자열과 비교할 때는 주의하세요.

13.7 JSON 처리의 변경사항

Rails 4.1에서 JSON 처리와 관련된 몇 가지 주요 변경사항이 있습니다.

13.7.1 MultiJSON 제거

MultiJSON은 수명이 다했으며 Rails에서 제거되었습니다.

현재 애플리케이션이 MultiJSON에 직접적으로 의존하고 있다면, 다음과 같은 옵션이 있습니다:

  1. Gemfile에 'multi_json'를 추가합니다. 단, 이는 향후 작동하지 않을 수 있습니다

  2. obj.to_jsonJSON.parse(str)를 사용하여 MultiJSON에서 벗어나도록 마이그레이션합니다.

MultiJson.load를 단순히 JSON.load로 대체하지 마세요. 해당 API는 임의의 Ruby 객체를 역직렬화하기 위한 것이며 일반적으로 안전하지 않습니다. 대신 JSON.parse를 사용하는 것이 좋습니다.

13.7.2 JSON gem 호환성

역사적으로, Rails는 JSON gem과 일부 호환성 문제가 있었습니다. Rails 애플리케이션 내에서 JSON.generateJSON.dump를 사용하면 예기치 않은 오류가 발생할 수 있었습니다.

Rails 4.1은 자체 인코더를 JSON gem으로부터 분리함으로써 이러한 문제를 해결했습니다. JSON gem API는 정상적으로 작동하지만, Rails 관련 기능에는 접근할 수 없습니다. 예를 들면:

class FooBar
  def as_json(options = nil)
    { foo: "bar" }
  end
end
irb> FooBar.new.to_json
=> "{\"foo\":\"bar\"}"
irb> JSON.generate(FooBar.new, quirks_mode: true)  
=> "\"#<FooBar:0x007fa80a481610>\""

13.7.3 새로운 JSON 인코더

Rails 4.1의 JSON 인코더는 JSON gem을 활용하기 위해 재작성되었습니다. 대부분의 애플리케이션에서는 투명하게 변경될 것입니다. 하지만 재작성의 일환으로 인코더에서 다음 기능들이 제거되었습니다:

  1. 순환 데이터 구조 감지
  2. encode_json 훅 지원
  3. BigDecimal 객체를 문자열 대신 숫자로 인코딩하는 옵션

애플리케이션이 이러한 기능들 중 하나에 의존하고 있다면, Gemfileactivesupport-json_encoder gem을 추가하여 해당 기능들을 다시 사용할 수 있습니다.

13.7.4 Time 객체의 JSON 표현

시간 컴포넌트(Time, DateTime, ActiveSupport::TimeWithZone)를 가진 객체의 #as_json은 이제 기본적으로 밀리초 정밀도를 반환합니다. 밀리초 정밀도가 없는 이전 동작을 유지해야 한다면, initializer에 다음과 같이 설정하세요:

ActiveSupport::JSON::Encoding.time_precision = 0

이렇게 하면 JSON 출력에 밀리초가 포함되지 않습니다.

13.8 인라인 콜백 블록 내에서 return 사용

이전에는 Rails가 인라인 콜백 블록에서 다음과 같은 방식으로 return을 사용하는 것을 허용했습니다:

class ReadOnlyModel < ActiveRecord::Base
  before_save { return false } # 나쁜 예
end

이 동작은 의도적으로 지원된 적이 없습니다. ActiveSupport::Callbacks의 내부 변경으로 인해 Rails 4.1에서는 더 이상 허용되지 않습니다. 인라인 callback 블록에서 return 문을 사용하면 callback이 실행될 때 LocalJumpError가 발생합니다.

return을 사용하는 인라인 callback 블록은 반환값을 평가하도록 리팩토링할 수 있습니다:

class ReadOnlyModel < ActiveRecord::Base
  before_save { false } # 좋음
end

대안으로, return을 선호한다면 명시적으로 메서드를 정의하는 것이 권장됩니다:

class ReadOnlyModel < ActiveRecord::Base
  before_save :before_save_callback # GOOD

  private
    def before_save_callback
      false 
    end
end

이 변경사항은 Active Record와 Active Model 콜백, 그리고 Action Controller의 필터(예: before_action)를 포함하여 Rails에서 콜백이 사용되는 대부분의 곳에 적용됩니다.

자세한 내용은 이 pull request를 참조하세요.

13.9 Active Record fixtures에 정의된 메소드

Rails 4.1은 각 fixture의 ERB를 별도의 context에서 평가하므로, fixture에 정의된 helper 메소드는 다른 fixture에서 사용할 수 없습니다.

여러 fixture에서 사용되는 helper 메소드는 test_helper.rb에서 새로 도입된 ActiveRecord::FixtureSet.context_class에 포함된 module에 정의되어야 합니다.

module FixtureFileHelpers
  def file_sha(path)
    OpenSSL::Digest::SHA256.hexdigest(File.read(Rails.root.join("test/fixtures", path)))
  end
end

# Fixture set의 컨텍스트 클래스에 FixtureFileHelpers 모듈을 포함시킵니다
ActiveRecord::FixtureSet.context_class.include FixtureFileHelpers

13.10 I18n 사용 가능한 locale 강제하기

Rails 4.1은 이제 I18n 옵션 enforce_available_locales의 기본값을 true로 설정합니다. 이는 I18n에 전달되는 모든 locale이 available_locales 목록에 선언되어 있어야 함을 의미합니다.

이를 비활성화하고 (I18n이 어떤 locale 옵션이든 허용하도록) 하려면 애플리케이션에 다음 설정을 추가하세요:

config.i18n.enforce_available_locales = false

이 설정을 통해 :en이나 다른 사용 가능한 locale을 포함하지 않은 locale이 있더라도 I18n에서 경고가 발생하지 않습니다.

이 옵션은 보안 조치로 추가되었으며, 사전에 알려진 경우가 아니라면 사용자 입력을 locale 정보로 사용할 수 없도록 하기 위한 것입니다. 따라서 매우 강력한 이유가 없다면 이 옵션을 비활성화하지 않는 것이 좋습니다.

13.11 Relation에서 호출되는 변경자(mutator) 메서드

Relation은 더 이상 #map!#delete_if 같은 변경자 메서드를 가지고 있지 않습니다. 이러한 메서드들을 사용하기 전에 #to_a를 호출하여 Array로 변환하세요.

이는 Relation에서 직접 변경자 메서드를 호출하는 코드에서 발생할 수 있는 이상한 버그와 혼란을 방지하기 위한 것입니다.

# 이렇게 하는 대신
Author.where(name: "Hank Moody").compact!

# 이제는 이렇게 해야 합니다
authors = Author.where(name: "Hank Moody").to_a
authors.compact!

13.12 Default Scope의 변화

Default scope는 더이상 연결된 조건에 의해 덮어쓰여지지 않습니다.

이전 버전에서는 모델에서 default_scope를 정의하면 동일 필드의 연결된 조건에 의해 덮어쓰여졌습니다. 이제는 다른 scope들처럼 병합됩니다.

이전:

class User < ActiveRecord::Base
  default_scope { where state: "pending" } 
  scope :active, -> { where state: "active" }
  scope :inactive, -> { where state: "inactive" }
end

User.all 
# "users" 테이블에서 "users"."state" = 'pending'인 모든 레코드를 선택

User.active
# "users" 테이블에서 "users"."state" = 'active'인 모든 레코드를 선택

User.where(state: "inactive")
# "users" 테이블에서 "users"."state" = 'inactive'인 모든 레코드를 선택

죄송하지만 번역할 문서가 제공되지 않았습니다. 번역하고 싶은 Rails 가이드 문서를 공유해 주시면 번역을 도와드리겠습니다.

class User < ActiveRecord::Base
  default_scope { where state: "pending" }  
  scope :active, -> { where state: "active" }
  scope :inactive, -> { where state: "inactive" }
end

User.all 
# "users" 테이블의 모든 레코드 중에서 "users"."state"가 'pending'인 것을 SELECT

User.active
# "users" 테이블에서 "users"."state"가 'pending'이고 "users"."state"가 'active'인 것을 SELECT 

User.where(state: "inactive")
# "users" 테이블에서 "users"."state"가 'pending'이고 "users"."state"가 'inactive'인 것을 SELECT

이전 동작을 얻으려면 unscoped, unscope, rewhere 또는 except를 사용하여 default_scope 조건을 명시적으로 제거해야 합니다.

class User < ActiveRecord::Base
  default_scope { where state: "pending" }
  scope :active, -> { unscope(where: :state).where(state: "active") }
  scope :inactive, -> { rewhere state: "inactive" }
end

User.all
# "users" 테이블에서 "users"."state" = 'pending'인 모든 레코드 조회

User.active
# "users" 테이블에서 "users"."state" = 'active'인 모든 레코드 조회

User.inactive
# "users" 테이블에서 "users"."state" = 'inactive'인 모든 레코드 조회

13.13 문자열에서 콘텐츠 렌더링하기

Rails 4.1에서는 render:plain, :html, :body 옵션이 도입되었습니다. 이러한 옵션들은 이제 문자열 기반 콘텐츠를 렌더링하는 데 선호되는 방식입니다. 응답을 어떤 content type으로 보낼지 지정할 수 있기 때문입니다.

  • render :plain은 content type을 text/plain으로 설정합니다
  • render :html은 content type을 text/html로 설정합니다
  • render :body는 content type 헤더를 설정하지 않습니다

보안 관점에서, 응답 본문에 마크업이 없을 것으로 예상되는 경우 render :plain을 사용해야 합니다. 대부분의 브라우저가 응답의 안전하지 않은 콘텐츠를 이스케이프 처리해주기 때문입니다.

향후 버전에서는 render :text 사용을 deprecate할 예정입니다. 따라서 더 정확한 :plain, :html, :body 옵션을 대신 사용하기 시작하세요. render :text를 사용하면 콘텐츠가 text/html로 전송되므로 보안 위험이 있을 수 있습니다.

13.14 PostgreSQL JSON과 hstore 데이터타입

Rails 4.1은 jsonhstore 컬럼을 문자열 키를 가진 Ruby Hash로 매핑합니다. 이전 버전에서는 HashWithIndifferentAccess가 사용되었습니다. 이는 심볼을 통한 접근이 더 이상 지원되지 않는다는 것을 의미합니다. 이는 json 또는 hstore 컬럼을 기반으로 한 store_accessors에도 해당됩니다. 반드시 문자열 키를 일관되게 사용하도록 하세요.

13.15 ActiveSupport::Callbacks의 명시적인 블록 사용

Rails 4.1에서는 ActiveSupport::Callbacks.set_callback을 호출할 때 명시적인 블록을 전달해야 합니다. 이 변경사항은 Rails 4.1 릴리스를 위해 ActiveSupport::Callbacks가 대부분 재작성되면서 발생했습니다.

# 이전 Rails 4.0
set_callback :save, :around, ->(r, &block) { stuff; result = block.call; stuff }

# Rails 4.1에서 변경됨
set_callback :save, :around, ->(r, block) { stuff; result = block.call; stuff }

14 Upgrading from Rails 3.2 to Rails 4.0

애플리케이션이 현재 3.2.x보다 오래된 Rails 버전을 사용중이라면, Rails 4.0으로 업그레이드하기 전에 먼저 Rails 3.2로 업그레이드해야 합니다.

다음 변경사항들은 애플리케이션을 Rails 4.0으로 업그레이드하기 위한 것입니다.

14.1 HTTP PATCH

Rails 4는 config/routes.rb에서 RESTful resource가 선언될 때 업데이트를 위한 주요 HTTP verb로 PATCH를 사용합니다. update 액션은 여전히 사용되며, PUT 요청도 계속해서 update 액션으로 라우팅됩니다. 따라서 표준 RESTful 라우트만 사용하는 경우에는 변경할 필요가 없습니다:

resources :users
<%= @user에 대한 form_for 도우미를 사용해서 |f| %>
class UsersController < ApplicationController
  def update
    # 변경 필요 없음; PATCH가 선호되며 PUT도 여전히 작동함.
  end
end

하지만 만약 PUT HTTP method를 사용하는 custom route와 함께 리소스를 업데이트하기 위해 form_for를 사용하는 경우에는 변경이 필요합니다:

resources :users do
  put :update_name, on: :member
end

:member 키워드는 행동이 리소스의 한 멤버에서 수행되어야 한다는 것을 나타냅니다. 이는 ID가 포함된 URL인 /users/1/update_name을 생성합니다.

<%= form_for [ :update_name, @user ] do |f| %>
class UsersController < ApplicationController
  def update_name
    # 변경 필요; form_for는 존재하지 않는 PATCH 라우트를 사용하려고 할 것입니다.
  end
end

해당 action이 public API에서 사용되지 않고 HTTP method를 자유롭게 변경할 수 있다면, route를 수정하여 put 대신 patch를 사용할 수 있습니다:

resources :users do
  patch :update_name, on: :member
end

:member 옵션을 사용하면 /users/:id/update_name과 같이 멤버 리소스의 URL을 정의할 수 있습니다.

PUT 요청은 Rails 4에서 현재처럼 /users/:id로 라우팅되어 update로 전달됩니다. 따라서 실제 PUT 요청을 받는 API가 있다면 정상적으로 동작할 것입니다. 라우터는 /users/:id로 오는 PATCH 요청도 update 액션으로 라우팅합니다.

만약 액션이 공개 API에서 사용되고 있어서 사용중인 HTTP 메서드를 변경할 수 없는 경우, form을 업데이트하여 PUT 메서드를 대신 사용할 수 있습니다:

<%= form_for [ :update_name, @user ], method: :put do |f| %>

이 코드는 form 을 생성하여 :update_name@user 를 통해 생성된 경로로 PUT 요청을 보냅니다.

PATCH와 이 변경이 이루어진 이유에 대해 자세히 알아보려면 Rails 블로그의 이 포스트를 참고하세요.

14.1.1 미디어 타입에 대한 참고사항

PATCH 동사의 정오표는 PATCH와 함께 'diff' 미디어 타입을 사용해야 한다고 명시하고 있습니다. 이러한 형식 중 하나가 JSON Patch입니다. Rails는 JSON Patch를 기본적으로 지원하지 않지만, 지원을 추가하는 것은 충분히 쉽습니다:

# 컨트롤러에서:
def update
  respond_to do |format|
    format.json do
      # 부분 업데이트 수행
      @article.update params[:article]
    end

    format.json_patch do
      # 복잡한 변경 수행
    end
  end
end
# config/initializers/json_patch.rb
Mime::Type.register "application/json-patch+json", :json_patch

JSON Patch가 최근에 RFC가 되었기 때문에, 아직 훌륭한 Ruby 라이브러리가 많지 않습니다. Aaron Patterson의 hana가 그런 gem 중 하나이지만, 명세의 최근 변경사항들을 완전히 지원하지는 않습니다.

14.2 Gemfile

Rails 4.0은 Gemfile에서 assets group을 제거했습니다. 업그레이드할 때 Gemfile에서 해당 라인을 제거해야 합니다. 또한 애플리케이션 파일(config/application.rb)을 업데이트해야 합니다:

# Gemfile에 나열된 gem들을 require합니다. :test, :development, :production과 같이
# 특정 환경에 제한된 gem들도 포함됩니다.
Bundler.require(*Rails.groups)

14.3 vendor/plugins

Rails 4.0에서는 더 이상 vendor/plugins에서 plugin을 로드하는 것을 지원하지 않습니다. plugin들을 gem으로 추출하고 Gemfile에 추가하여 교체해야 합니다. gem으로 만들지 않기로 선택한 경우, 예를 들어 lib/my_plugin/*로 옮기고 config/initializers/my_plugin.rb에 적절한 initializer를 추가할 수 있습니다.

14.4 Active Record

  • Rails 4.0에서는 연관관계에서의 일부 불일치로 인해 Active Record의 identity map이 제거되었습니다. 애플리케이션에서 수동으로 활성화했다면, 더 이상 효과가 없는 다음 설정을 제거해야 합니다: config.active_record.identity_map.

  • collection 연관관계의 delete 메서드는 이제 destroy 메서드처럼 record 외에도 IntegerString 타입의 record id를 인자로 받을 수 있습니다. 이전에는 이러한 인자에 대해 ActiveRecord::AssociationTypeMismatch를 발생시켰습니다. Rails 4.0부터는 delete가 삭제하기 전에 자동으로 주어진 id와 일치하는 record를 찾습니다.

  • Rails 4.0에서는 column이나 table의 이름이 변경될 때 관련 index들도 함께 이름이 변경됩니다. index 이름을 변경하는 migration이 있다면, 더 이상 필요하지 않습니다.

  • Rails 4.0에서는 serialized_attributesattr_readonly를 클래스 메서드로만 변경했습니다. 이제 deprecated된 인스턴스 메서드는 사용하지 않아야 합니다. 클래스 메서드를 사용하도록 변경해야 합니다. 예: self.serialized_attributes에서 self.class.serialized_attributes로.

  • 기본 coder를 사용할 때, serialized 속성에 nil을 할당하면 YAML을 통해 nil 값을 전달하는 대신 ("--- \n...\n") 데이터베이스에 NULL로 저장됩니다.

  • Rails 4.0에서는 Strong Parameters를 위해 attr_accessibleattr_protected 기능이 제거되었습니다. 원활한 업그레이드를 위해 Protected Attributes gem을 사용할 수 있습니다.

  • Protected Attributes를 사용하지 않는다면, whitelist_attributesmass_assignment_sanitizer 옵션과 같은 이 gem과 관련된 옵션들을 제거할 수 있습니다.

  • Rails 4.0에서는 scope가 Proc이나 lambda 같은 callable 객체를 사용하도록 요구합니다:

    scope :active, where(active: true)
    
    # 다음과 같이 변경
    scope :active, -> { where active: true }
    
  • Rails 4.0에서는 ActiveRecord::Fixtures 대신 ActiveRecord::FixtureSet을 사용하도록 deprecated 되었습니다.

  • Rails 4.0에서는 ActiveRecord::TestCase 대신 ActiveSupport::TestCase를 사용하도록 deprecated 되었습니다.

  • Rails 4.0에서는 구식 해시 기반 finder API가 deprecated 되었습니다. 이는 이전에 "finder options"를 받았던 메서드들이 더 이상 그렇지 않다는 것을 의미합니다. 예를 들어, Book.find(:all, conditions: { name: '1984' })Book.where(name: '1984')를 사용하도록 deprecated 되었습니다.

  • find_by_...find_by_...!를 제외한 모든 동적 메서드가 deprecated 되었습니다. 변경 사항은 다음과 같습니다:

    • find_all_by_...where(...)로 변경
    • find_last_by_...where(...).last로 변경
    • scoped_by_...where(...)로 변경
    • find_or_initialize_by_...find_or_initialize_by(...)로 변경
    • find_or_create_by_...find_or_create_by(...)로 변경
  • where(...)는 이전 finder들처럼 배열이 아닌 relation을 반환한다는 점에 주의하세요. 배열이 필요한 경우 where(...).to_a를 사용하세요.

  • 이러한 동등한 메서드들은 이전 구현과 동일한 SQL을 실행하지 않을 수 있습니다.

  • 이전 finder들을 다시 활성화하려면 activerecord-deprecated_finders gem을 사용할 수 있습니다.

  • Rails 4.0에서는 has_and_belongs_to_many 관계의 기본 join table이 두 번째 테이블 이름에서 공통 접두사를 제거하도록 변경되었습니다. 공통 접두사를 가진 모델 간의 기존 has_and_belongs_to_many 관계는 join_table 옵션으로 지정되어야 합니다. 예를 들어:

class CatalogCategory < ActiveRecord::Base
  has_and_belongs_to_many :catalog_products, join_table: "catalog_categories_catalog_products"
end

class CatalogProduct < ActiveRecord::Base
  has_and_belongs_to_many :catalog_categories, join_table: "catalog_categories_catalog_products"
end
  • prefix는 scope도 고려하므로, Catalog::CategoryCatalog::Product 또는 Catalog::CategoryCatalogProduct 간의 관계도 이와 유사하게 업데이트해야 합니다.

14.5 Active Resource

Rails 4.0에서는 Active Resource를 독립적인 gem으로 분리했습니다. 만약 이 기능이 여전히 필요하다면 GemfileActive Resource gem을 추가하면 됩니다.

14.6 Active Model

  • Rails 4.0에서는 ActiveModel::Validations::ConfirmationValidator로 에러를 연결하는 방식이 변경되었습니다. 이제 확인 유효성 검사가 실패하면 에러는 attribute 대신 :#{attribute}_confirmation에 연결됩니다.

  • Rails 4.0에서는 ActiveModel::Serializers::JSON.include_root_in_json의 기본값이 false로 변경되었습니다. 이제 Active Model Serializer와 Active Record 객체가 동일한 기본 동작을 가집니다. 이는 config/initializers/wrap_parameters.rb 파일에서 다음 옵션을 주석 처리하거나 제거할 수 있다는 것을 의미합니다:

    # Disable root element in JSON by default.
    # ActiveSupport.on_load(:active_record) do
    #   self.include_root_in_json = false
    # end
    

14.7 Action Pack

  • Rails 4.0은 ActiveSupport::KeyGenerator를 도입하여 서명된 쿠키를 생성하고 검증하는 데 기반으로 사용합니다(다른 용도도 있음). 기존의 secret_token을 유지하고 새로운 secret_key_base를 추가하면 Rails 3.x에서 생성된 기존 서명된 쿠키들이 자동으로 업그레이드됩니다.

    # config/initializers/secret_token.rb
    Myapp::Application.config.secret_token = "existing secret token"
    Myapp::Application.config.secret_key_base = "new secret key base"
    

    사용자 기반의 100%가 Rails 4.x를 사용하고 Rails 3.x로 롤백할 필요가 없다고 확신할 때까지 secret_key_base를 설정하지 않는 것이 좋습니다. 이는 Rails 4.x에서 새로운 secret_key_base를 기반으로 서명된 쿠키가 Rails 3.x와 하위 호환되지 않기 때문입니다. 업그레이드가 완료되었다고 확신할 때까지 기존의 secret_token을 유지하고, 새로운 secret_key_base를 설정하지 않은 채로 deprecation 경고를 무시해도 됩니다.

    외부 애플리케이션이나 JavaScript가 Rails 앱의 서명된 세션 쿠키(또는 일반적인 서명된 쿠키)를 읽을 수 있어야 하는 경우, 이러한 의존성을 분리할 때까지 secret_key_base를 설정하지 마세요.

  • Rails 4.0은 secret_key_base가 설정된 경우 쿠키 기반 세션의 내용을 암호화합니다. Rails 3.x는 쿠키 기반 세션의 내용을 서명했지만 암호화하지는 않았습니다. 서명된 쿠키는 앱에서 생성되었다는 것이 검증되고 변조가 불가능하다는 점에서 "안전"합니다. 하지만 최종 사용자가 내용을 볼 수 있으며, 내용을 암호화하면 성능 저하 없이 이러한 문제/우려를 제거할 수 있습니다.

    암호화된 세션 쿠키로의 이전에 대한 자세한 내용은 Pull Request #9978을 참조하세요.

  • Rails 4.0은 ActionController::Base.asset_path 옵션을 제거했습니다. assets pipeline 기능을 사용하세요.

  • Rails 4.0은 ActionController::Base.page_cache_extension 옵션을 deprecated 했습니다. 대신 ActionController::Base.default_static_extension을 사용하세요.

  • Rails 4.0은 Action Pack에서 Action 및 Page 캐싱을 제거했습니다. 컨트롤러에서 caches_action을 사용하려면 actionpack-action_caching gem을, caches_page를 사용하려면 actionpack-page_caching gem을 추가해야 합니다.

  • Rails 4.0은 XML 파라미터 파서를 제거했습니다. 이 기능이 필요한 경우 actionpack-xml_parser gem을 추가해야 합니다.

  • Rails 4.0은 nil을 반환하는 심볼이나 proc을 사용하는 기본 layout 조회를 변경했습니다. "레이아웃 없음" 동작을 얻으려면 nil 대신 false를 반환하세요.

  • Rails 4.0은 기본 memcached 클라이언트를 memcache-client에서 dalli로 변경했습니다. 업그레이드하려면 Gemfilegem "dalli"를 추가하면 됩니다.

  • Rails 4.0은 컨트롤러에서 dom_iddom_class 메서드를 deprecated 했습니다(뷰에서는 계속 사용 가능). 이 기능이 필요한 컨트롤러에 ActionView::RecordIdentifier 모듈을 포함해야 합니다.

  • Rails 4.0은 link_to 헬퍼의 :confirm 옵션을 deprecated 했습니다. 대신 data 속성을 사용해야 합니다(예: data: { confirm: 'Are you sure?' }). 이 deprecation은 이를 기반으로 하는 헬퍼(link_to_iflink_to_unless 등)에도 적용됩니다.

  • Rails 4.0은 assert_generates, assert_recognizes, assert_routing의 작동 방식을 변경했습니다. 이제 이러한 assertions는 ActionController::RoutingError 대신 Assertion을 발생시킵니다.

  • Rails 4.0은 충돌하는 명명된 라우트가 정의되면 ArgumentError를 발생시킵니다. 이는 명시적으로 정의된 명명된 라우트나 resources 메서드로 인해 발생할 수 있습니다. 다음은 example_path라는 라우트가 충돌하는 두 예시입니다:

    get "one" => "test#example", as: :example
    get "two" => "test#example", as: :example
    
    resources :examples
    get "clashing/:id" => "test#example", as: :example
    

첫 번째 경우에는 여러 route에 대해 동일한 이름을 사용하지 않으면 됩니다. 두 번째 경우에는 resources 메서드가 제공하는 only 또는 except 옵션을 사용하여 Routing Guide에 자세히 설명된 대로 생성되는 route를 제한할 수 있습니다.

  • Rails 4.0은 유니코드 문자 route를 그리는 방식도 변경했습니다. 이제 유니코드 문자 route를 직접 그릴 수 있습니다. 이미 이러한 route를 그린 경우 다음과 같이 변경해야 합니다:

    get Rack::Utils.escape("こんにちは"), controller: "welcome", action: "index"
    

    다음과 같이 변경:

    get "こんにちは", controller: "welcome", action: "index"
    
  • Rails 4.0은 match를 사용하는 route가 반드시 request method를 지정하도록 요구합니다. 예시:

    # Rails 3.x
    match "/" => "root#index"
    
    # 다음과 같이 변경
    match "/" => "root#index", via: :get
    
    # 또는
    get "/" => "root#index"
    
  • Rails 4.0은 ActionDispatch::BestStandardsSupport middleware를 제거했습니다. <!DOCTYPE html>는 이미 https://msdn.microsoft.com/en-us/library/jj676915(v=vs.85).aspx 에 따라 standards mode를 트리거하며 ChromeFrame 헤더는 config.action_dispatch.default_headers로 이동되었습니다.

    애플리케이션 코드에서 middleware에 대한 참조도 모두 제거해야 합니다. 예시:

    # 예외 발생
    config.middleware.insert_before(Rack::Lock, ActionDispatch::BestStandardsSupport)
    

    또한 환경 설정에서 config.action_dispatch.best_standards_support를 확인하고 있다면 제거하십시오.

  • Rails 4.0은 config.action_dispatch.default_headers를 설정하여 HTTP 헤더를 구성할 수 있습니다. 기본값은 다음과 같습니다:

    config.action_dispatch.default_headers = {
      "X-Frame-Options" => "SAMEORIGIN",
      "X-XSS-Protection" => "1; mode=block"
    }
    

애플리케이션이 특정 페이지를 <frame> 또는 <iframe>에서 로드해야 하는 경우, X-Frame-Options를 명시적으로 ALLOW-FROM ... 또는 ALLOWALL로 설정해야 할 수 있습니다.

  • Rails 4.0에서는 asset precompile 시 vendor/assetslib/assets에서 JS/CSS가 아닌 asset들을 자동으로 복사하지 않습니다. Rails 애플리케이션과 엔진 개발자들은 이러한 asset들을 app/assets에 넣거나 config.assets.precompile을 설정해야 합니다.

  • Rails 4.0에서는 액션이 요청 포맷을 처리하지 못할 때 ActionController::UnknownFormat이 발생합니다. 기본적으로 이 예외는 406 Not Acceptable로 응답하지만 이제 이를 재정의할 수 있습니다. Rails 3에서는 항상 406 Not Acceptable이 반환되었고 재정의할 수 없었습니다.

  • Rails 4.0에서는 ParamsParser가 요청 파라미터를 파싱하는데 실패할 경우 일반적인 ActionDispatch::ParamsParser::ParseError 예외가 발생합니다. 예를 들어 낮은 수준의 MultiJson::DecodeError 대신 이 예외를 rescue해야 합니다.

  • Rails 4.0에서는 URL 접두사로 제공되는 앱에 엔진이 마운트될 때 SCRIPT_NAME이 적절하게 중첩됩니다. 더 이상 덮어쓴 URL 접두사를 해결하기 위해 default_url_options[:script_name]을 설정할 필요가 없습니다.

  • Rails 4.0은 ActionController::Integration 대신 ActionDispatch::Integration을 사용하도록 권장합니다.

  • Rails 4.0은 ActionController::IntegrationTest 대신 ActionDispatch::IntegrationTest를 사용하도록 권장합니다.

  • Rails 4.0은 ActionController::PerformanceTest 대신 ActionDispatch::PerformanceTest를 사용하도록 권장합니다.

  • Rails 4.0은 ActionController::AbstractRequest 대신 ActionDispatch::Request를 사용하도록 권장합니다.

  • Rails 4.0은 ActionController::Request 대신 ActionDispatch::Request를 사용하도록 권장합니다.

  • Rails 4.0은 ActionController::AbstractResponse 대신 ActionDispatch::Response를 사용하도록 권장합니다.

  • Rails 4.0은 ActionController::Response 대신 ActionDispatch::Response를 사용하도록 권장합니다.

  • Rails 4.0은 ActionController::Routing 대신 ActionDispatch::Routing를 사용하도록 권장합니다.

14.8 Active Support

Rails 4.0에서는 j가 이미 ActionView::Helpers::JavaScriptHelper#escape_javascript에서 사용되고 있기 때문에 ERB::Util#json_escape의 별칭인 j를 제거했습니다.

14.8.1 Cache

Rails 3.x와 4.0 사이에 캐싱 방식이 변경되었습니다. cache namespace를 변경하고 빈 캐시로 배포해야 합니다.

14.9 Helpers 로딩 순서

한 개 이상의 디렉토리에서 helper를 로딩하는 순서가 Rails 4.0에서 변경되었습니다. 이전에는 모든 helper를 수집한 후 알파벳순으로 정렬했습니다. Rails 4.0으로 업그레이드한 후에는 helper가 로딩된 디렉토리의 순서를 유지하고 각 디렉토리 내에서만 알파벳순으로 정렬됩니다. helpers_path 파라미터를 명시적으로 사용하지 않는 한, 이 변경사항은 engine에서 helper를 로딩하는 방식에만 영향을 미칩니다. 만약 이 순서에 의존하고 있다면, 업그레이드 후에 올바른 메서드들이 사용 가능한지 확인해야 합니다. engine이 로딩되는 순서를 변경하고 싶다면, config.railties_order= 메서드를 사용할 수 있습니다.

14.10 Active Record Observer와 Action Controller Sweeper

ActiveRecord::ObserverActionController::Caching::Sweeperrails-observers gem으로 분리되었습니다. 이러한 기능이 필요한 경우 rails-observers gem을 추가해야 합니다.

14.11 sprockets-rails

  • assets:precompile:primaryassets:precompile:all이 제거되었습니다. 대신 assets:precompile을 사용하세요.
  • config.assets.compress 옵션은 다음과 같이 config.assets.js_compressor로 변경되어야 합니다:

    config.assets.js_compressor = :uglifier
    

14.12 sass-rails

  • 두 개의 인자를 가진 asset-url은 더 이상 사용되지 않습니다. 예를 들어: asset-url("rails.png", image)asset-url("rails.png")가 됩니다.

15 Rails 3.1에서 Rails 3.2로 업그레이드

현재 애플리케이션이 Rails 3.1.x 이전 버전이라면, Rails 3.2로 업그레이드를 시도하기 전에 먼저 Rails 3.1로 업그레이드해야 합니다.

다음 변경사항들은 애플리케이션을 최신 Rails 3.2.x 버전으로 업그레이드하기 위한 것입니다.

15.1 Gemfile

Gemfile에 다음과 같은 변경사항을 적용하세요.

gem "rails", "3.2.21"

group :assets do
  gem "sass-rails",   "~> 3.2.6"
  gem "coffee-rails", "~> 3.2.2"
  gem "uglifier",     ">= 1.0.3"
end

15.2 config/environments/development.rb

development 환경에 추가해야 할 몇 가지 새로운 configuration 설정이 있습니다:

# Active Record 모델에 대한 mass assignment 보호에 대해 예외 발생시키기
config.active_record.mass_assignment_sanitizer = :strict

# 지정된 시간보다 오래 걸리는 쿼리에 대해 쿼리 계획 로깅하기
# (SQLite, MySQL, PostgreSQL에서 동작)
config.active_record.auto_explain_threshold_in_seconds = 0.5

15.3 config/environments/test.rb

mass_assignment_sanitizer 설정은 config/environments/test.rb 파일에도 추가되어야 합니다:

# Active Record 모델에 대한 mass assignment 보호에서 예외 발생시키기
config.active_record.mass_assignment_sanitizer = :strict

15.4 vendor/plugins

Rails 3.2는 vendor/plugins를 deprecate했고 Rails 4.0에서는 완전히 제거될 예정입니다. Rails 3.2 업그레이드의 필수 사항은 아니지만, plugin들을 gem으로 추출하고 Gemfile에 추가하는 방식으로 교체하기 시작할 수 있습니다. gem으로 만들지 않기로 선택했다면, 예를 들어 lib/my_plugin/*로 옮기고 config/initializers/my_plugin.rb에 적절한 initializer를 추가할 수 있습니다.

15.5 Active Record

Option :dependent => :restrictbelongs_to에서 제거되었습니다. 관련 객체가 있는 경우 객체 삭제를 방지하려면 :dependent => :destroy를 설정하고 관련된 객체의 destroy 콜백에서 연관관계의 존재 여부를 확인한 후 false를 반환하면 됩니다.

16 Rails 3.0에서 Rails 3.1로 업그레이드하기

현재 애플리케이션이 3.0.x 이전 버전의 Rails를 사용중이라면, Rails 3.1 업데이트를 시도하기 전에 먼저 Rails 3.0으로 업그레이드해야 합니다.

다음 변경사항들은 Rails의 마지막 3.1.x 버전인 Rails 3.1.12로 애플리케이션을 업그레이드하기 위한 것입니다.

16.1 Gemfile

Gemfile에 다음과 같이 변경사항을 적용하세요.

gem "rails", "3.1.12"
gem "mysql2"

# 새로운 asset pipeline에 필요함
group :assets do
  gem "sass-rails",   "~> 3.1.7"
  gem "coffee-rails", "~> 3.1.1"
  gem "uglifier",     ">= 1.0.3"
end

# jQuery는 Rails 3.1의 기본 JavaScript 라이브러리입니다
gem "jquery-rails"

16.2 config/application.rb

asset pipeline은 다음과 같은 추가 사항이 필요합니다:

config.assets.enabled = true
config.assets.version = "1.0"

Asset Pipeline을 활성화하거나 비활성화합니다. 기본값은 true 입니다. version 설정은 asset이 만료되도록 강제하기 위해 모든 asset URL의 suffix로 사용되는 문자열입니다.

만약 애플리케이션이 리소스로 "/assets" 라우트를 사용하고 있다면, 충돌을 피하기 위해 assets에 사용되는 prefix를 변경할 수 있습니다:

# 기본값은 '/assets'
config.assets.prefix = "/asset-files"

16.3 config/environments/development.rb

RJS 설정인 config.action_view.debug_rjs = true를 제거하세요.

asset pipeline을 활성화한 경우 다음 설정들을 추가하세요:

# asset을 압축하지 않음
config.assets.compress = false

# asset을 로드하는 라인을 확장함
config.assets.debug = true

16.4 config/environments/production.rb

다시 한번 말씀드리면, 아래의 대부분 변경사항들은 asset pipeline을 위한 것입니다. Asset Pipeline 가이드에서 이것들에 대해 더 자세히 읽어볼 수 있습니다.

JavaScript와 CSS 압축

config.assets.compress = true

미리 컴파일된 asset이 없을 경우 assets pipeline으로 폴백하지 않음

config.assets.compile = false

assets URL에 대한 digest 생성

config.assets.digest = true

기본값은 Rails.root.join("public/assets")

config.assets.manifest = YOUR_PATH

추가 assets 미리 컴파일 (application.js, application.css 및 모든 JS/CSS가 아닌 파일들은 이미 추가됨)

config.assets.precompile += %w( admin.js admin.css )

SSL을 통한 앱 접근 강제, Strict-Transport-Security 사용, 보안 쿠키 사용

config.force_ssl = true

16.5 config/environments/test.rb

테스트 환경에 다음 내용을 추가하여 성능 테스트에 도움을 받을 수 있습니다:

# 성능을 위한 Cache-Control과 함께 테스트용 static asset 서버 설정
config.public_file_server.enabled = true
config.public_file_server.headers = {
  "Cache-Control" => "public, max-age=3600"
}

16.6 config/initializers/wrap_parameters.rb

매개변수를 중첩된 hash로 래핑하려면 다음 내용으로 이 파일을 추가하세요. 새로운 애플리케이션에서는 이것이 기본적으로 활성화되어 있습니다.

# 이 파일을 수정한 후에는 서버를 재시작하세요.
# 이 파일에는 기본적으로 활성화되어 있는 ActionController::ParamsWrapper의 
# 설정이 포함되어 있습니다.

# JSON용 parameter wrapping을 활성화합니다. :format을 빈 배열로 설정하여 비활성화할 수 있습니다.
ActiveSupport.on_load(:action_controller) do
  wrap_parameters format: [:json]
end

# 기본적으로 JSON의 root element를 비활성화합니다.
ActiveSupport.on_load(:active_record) do
  self.include_root_in_json = false
end

16.7 config/initializers/session_store.rb

session key를 새로운 것으로 변경하거나 모든 session을 제거해야 합니다:

# in config/initializers/session_store.rb
AppName::Application.config.session_store :cookie_store, key: "SOMETHINGNEW"

"or"은 대안이나 선택을 나타내는 "또는"이라고 번역됩니다.

$ bin/rake db:sessions:clear

16.8 뷰에서 asset helper 참조의 :cache와 :concat 옵션 제거하기

  • Asset Pipeline을 사용하면서 :cache와 :concat 옵션은 더 이상 사용되지 않으므로, 뷰에서 이러한 옵션들을 삭제하세요.


맨 위로