Зарегистрируйтесь, чтобы продолжить обучение

Конфигурация Ruby On Rails

В этом уроке рассмотрим конфигурацию приложений на Ruby on Rails. Мы рассмотрим, как управлять окружениями в Rails, что позволит адаптировать поведение приложения в зависимости от его использования, будь то разработка, тестирование или продакшн. Также мы обсудим использование инициалайзеров для настройки параметров приложения, способы хранения конфиденциальной информации, а также познакомимся с инструментами, такими как Spring и Puma, которые помогут оптимизировать процесс разработки и развертывания. Начнем с работы с окружениями в Rails, чтобы понять, как правильно настраивать приложение для различных сценариев использования.

Окружения

В Ruby on Rails по умолчанию создаются три основных окружения: development, test и production. Каждое из этих окружений предназначено для выполнения различных задач в процессе разработки и развертывания приложения.

Development

Окружение для разработки, в котором пишем код и разрабатываем приложение. Здесь включены инструменты для отладки, изменения применяются на лету, что позволяет быстро видеть результаты работы. Например, при возникновении исключений отображаются подробные сообщения об ошибках с указанием стека вызовов.

Доступны различные инструменты и библиотеки, такие как pry или byebug, которые помогают выполнять отладку. В development-окружении можно запускать интерактивные консоли (rails console), что позволяет выполнять команды и тестировать код в реальном времени.

Изменения в коде автоматически применяются без необходимости перезапуска сервера. Это позволяет быстро видеть результаты своих изменений.

Уровень логирования в development-окружении настроен на debug, что позволяет записывать все действия приложения, включая запросы, ответы и внутренние операции. Это помогает анализировать поведение приложения и выявлять проблемы.

Кэширование обычно отключено или настроено на минимальный уровень. Это позволяет видеть актуальные изменения в приложении без задержек, связанных с кэшированием.

Test

Окружение test в Ruby on Rails предназначено для автоматизированного тестирования приложения.

Тесты запускаются в изолированном окружении, что позволяет избежать влияния одного теста на другой. Это достигается за счет использования отдельной базы данных для тестов, которая обычно создается и очищается перед каждым запуском тестов. Тесты могут быть запущены автоматически с помощью различных инструментов, таких как RSpec или Minitest.

В test-окружении кэширование обычно отключено, чтобы гарантировать, что тесты всегда работают с актуальными данными и кодом. Это позволяет избежать неожиданных результатов из-за кэшированных данных.

Уровень логирования в test-окружении может быть настроен на более низкий уровень (например, warn или error), чтобы минимизировать объем записываемых логов и сосредоточиться на важных сообщениях об ошибках.

Для создания тестовых данных в test-окружении часто используются фикстуры или библиотеки для создания тестовых данных. Это позволяет разработчикам легко генерировать необходимые данные для тестов.

После выполнения тестов выводится отчет о результатах, который показывает, какие тесты прошли успешно, а какие провалились.

Test-окружение часто интегрируется с системами непрерывной интеграции и развертывания (CI/CD), что позволяет автоматически запускать тесты при каждом изменении кода.

Production

Это окружение, в котором приложение развернуто для конечных пользователей. Здесь важна стабильность и производительность, поэтому настройки могут отличаться от других окружений. В production-окружении используются оптимизированные настройки, которые обеспечивают максимальную производительность приложения. Например, включается кэширование, отключаются отладочные инструменты и используется более быстрый веб-сервер.

Уровень логирования в production обычно настроен на более высокий уровень (например, error или warn), чтобы минимизировать объем записываемых логов и сосредоточиться на критических ошибках. В отличие от development-окружения, где логируются все действия, в production важно избегать избыточной информации.

В production-окружении применяются более строгие меры безопасности. Например, используется HTTPS для защиты данных пользователей.

Используется отдельная база данных, которая отличается от баз данных в development и test. Это позволяет избежать случайного изменения или удаления данных пользователей.

В production-окружении отладка ограничена. Разработчики не должны иметь доступ к отладочным инструментам, чтобы избежать потенциальных уязвимостей. Вместо этого используются инструменты мониторинга и алерты для отслеживания состояния приложения.

Создание своего окружения

Rails управляет окружениями с помощью файлов, расположенных в директории config/environments. Каждый файл содержит настройки, специфичные для соответствующего окружения. Например, в файле config/environments/development.rb можно настроить параметры логирования, кэширования и другие аспекты, которые будут применяться только в режиме разработки.

Если нам необходимо создать новое окружение, например, staging, нам нужно выполнить несколько шагов:

  1. Создадим новый файл в директории config/environments, назвав его staging.rb и добавим туда конфиг:

      require_relative "development"
    
      Rails.application.configure do
        # Staging overrides
        config.assume_ssl = false
      end
    

    Строка require_relative "development" загружает настройки из файла development.rb и находится в директории development.rb. Это означает, что все настройки, определенные в окружении разработки, будут унаследованы в окружении staging. Таким образом, можем использовать уже существующие настройки и переопределять только те, которые нужны для staging.

    Rails.application.configure do блок кода используется для настройки параметров приложения. Внутри этого блока мы можем изменять конфигурацию Rails, добавляя или переопределяя параметры.

    config.assume_ssl = false устанавливает значение параметра assume_ssl в false. Приложение не будет предполагать, что соединение является безопасным (SSL). В контексте staging-окружения это может быть полезно, если вы не используется HTTPS для тестирования или если мы хотим проверить функциональность приложения в условиях, когда SSL не активен.

  2. Обновим настройки подключения к базе данных, добавив соответствующий блок в файл database.yml:

   staging:
     <<: *default
     database: db/staging.sqlite3

Ключ staging: это название окружения, для которого настраиваются параметры базы данных. <<: *default эта строка использует YAML-синтаксис для наследования настроек из блока, который был определен ранее в файле как default. Звездочка (*) указывает на то, что мы хотим использовать все настройки, определенные в блоке default. Это позволяет избежать дублирования кода и упрощает управление конфигурацией, так как все общие настройки можно определить в одном месте. database: db/staging.sqlite3 Эта строка указывает, что база данных для окружения staging будет находиться в файле db/staging.sqlite3. Это означает, что при работе в окружении staging приложение будет использовать SQLite базу данных, хранящуюся в этом файле.

  1. Запустим сервер в нужном окружении:
  bin/rails s -e staging

Также мы можем запустить консоль в нужном окружении, установив глобальную переменную окружения:

RAILS_ENV=staging bin/rails c
# Находимся внутри консоли Rails
Loading staging environment (Rails 7.1.5.1)
irb(main):001> Rails.env
=> "staging"
irb(main):002>

Мы можем получить информацию о том, в каком окружении запущено приложение с помощью метода Rails.env. К примеру мы можем проверить, запущено ли приложение в production-среде и если да, то выполним первую ветку условия:

  if Rails.env.production?
    # сработает только если Rails.env == production
  else
    # ...
  end

Теперь, когда мы разобрались с созданием и настройкой окружений, перейдем к следующему аспекту конфигурации приложений в Ruby on Rails — инициалайзерам.

Инициалайзеры

Инициалайзеры в Ruby on Rails — это специальные файлы, которые загружаются при старте приложения и позволяют выполнять код для настройки различных компонентов и библиотек. Они находятся в директории config/initializers и имеют расширение .rb. Каждый файл в этой директории выполняется в алфавитном порядке, что позволяет организовать и структурировать настройки.

В инициалайзерах Ruby on Rails можно размещать различные настройки и конфигурации, которые будут выполняться при старте приложения. Пример настройки devise в hexlet-cv:

# config/initializers/devise.rb

Devise.setup do |config|
  config.mailer_sender = ENV.fetch('EMAIL_FROM')
  require 'devise/orm/active_record'
  config.case_insensitive_keys = [:email]
  config.strip_whitespace_keys = [:email]
  config.skip_session_storage = [:http_auth]
  config.stretches = Rails.env.test? ? 1 : 11
  config.reconfirmable = true
  config.expire_all_remember_me_on_sign_out = true
  config.password_length = 6..128
  config.email_regexp = /\A[^@\s]+@[^@\s]+\z/
  config.reset_password_within = 6.hours
end

В инициалайзерах можно определять глобальные константы, которые будут использоваться в приложении. Это может быть полезно для хранения настроек, таких как типы занятости, уровни должностей и другие параметры.

Пример инициализатора констант, из проекта hexlet-cv:

# config/initializers/constants.rb

EMPLOYMENT_TYPES = %i[full-time part-time contract temporary seasonal internship].freeze
POSITION_LEVELS = %i[intern junior middle senior].freeze
TAG_MAX_LENGTH = 40

Если приложение взаимодействует с внешними API, мы можем настроить параметры, такие как базовые URL, таймауты и заголовки.

# config/initializers/openapi.rb
OpenAI.configure do |config|
  config.access_token = ENV.fetch('OPENAI_ACCESS_TOKEN', nil)
  # config.organization_id = ENV.fetch('OPENAI_ORGANIZATION_ID') # Optional.
end

В инициализаторах могут быть объявлены и другие настройки, такие как логирование, кэширование, регистрация классов и модулей.

Хранение конфиденциальной информации

В Ruby on Rails работа с секретами и конфиденциальной информацией, такой как API-ключи, пароли и другие чувствительные данные, осуществляется с помощью нескольких подходов. Вот основные из них:

credentials.yml.enc

Файл credentials.yml.enc зашифрован и позволяет хранить конфиденциальные данные. Командой rails credentials:edit откроется файл в редакторе по умолчанию, где вы мы можем добавлять ключи и значения в формате YAML. Пример содержимого:

  aws:
    access_key_id: your_access_key_id
    secret_access_key: your_secret_access_key

Также мы можем открыть файл в определенном редакторе:

  # Редактируем в VSCode
  EDITOR="code -w" bin/rails credentials:edit
  Editing config/credentials.yml.enc...
  # редактируем файл и сохраняем
  File encrypted and saved.

Использовать секреты в коде мы можем, обратившись к Rails.application.credentials:

  access_key_id = Rails.application.credentials.aws[:access_key_id]
  secret_access_key = Rails.application.credentials.aws[:secret_access_key]
  # ...

Файл credentials.yml.enc шифруется с помощью файла-ключа config/master.key. Этот файл надо надежно хранить и не выкладывать в открытый доступ.

Переменные окружения

Другой распространенный способ хранения секретов — использование переменных окружения. Это позволяет избежать хранения конфиденциальной информации в коде.

Для разработки можно использовать гем dotenv-rails. Он позволяет описать переменные окружения внутри файла .env и загрузить их оттуда.

Файл .env обычно не хранят внутри репозитория, и его копируют из файла-шаблона. Пример файла из hexlet-cv:

EMAIL_FROM=local@local.local
GITHUB_APP_SECRET=1cbaa8d7eaa9897204615ae07383791bf3c6113d
GITHUB_APP_ID=4bf7b244da515541298a

RECAPTCHA_SITE_KEY=1111key2222
RECAPTCHA_SECRET_KEY='$eCr3T'

HOST=localhost

OPENAI_ACCESS_TOKEN=1235fff12345
PASSWORD_SPECIAL_USER=
EMAIL_SPECIAL_USER=special@test.io

# test key for recapcha https://github.com/MTG/freesound/issues/879
RECAPTCHA_SITE_KEY=6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI
RECAPTCHA_SECRET_KEY=6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe
HABR_ACCESS_TOKEN=111222zzz
N8N_ACCESS_TOKEN=111xvxv

Файл содержит примеры значений и пустые переменные, которые нужно заполнить самостоятельно после копирования файла из шаблона. Необходимые переменные будут храниться в специальном хеше ENV:

access_token = ENV.fetch('OPENAI_ACCESS_TOKEN', nil)

Spring

Spring — это инструмент для предварительной загрузки приложений на Ruby on Rails, который значительно ускоряет процесс разработки, позволяя избежать повторной инициализации приложения при каждом запуске команд, таких как тесты, миграции и другие задачи.

Spring предварительно загружает ваше приложение в фоновом режиме, так что когда мы запускаем тесты, миграции или другие задачи Rake, вам не нужно ждать загрузки приложения. Spring делает эти команды намного более быстрыми для выполнения.

Поскольку Rails призывает нас загружать все гемы при запуске (помещая Bundler.require в config/application.rb), со временем время загрузки Rails-приложения может стать значительным. Это особенно заметно во время модульного тестирования, поскольку мы хотим получать обратную связь как можно скорее, и не ждать слишком долго загрузки приложения. Поэтому Spring сокращает время запуском команды rails test и просмотром запущенных тестов.

По умолчанию Spring выключен. Его необходимо добавить в Gemfile и выполнить bundle install:

# Gemfile
group :development do
  gem "spring"
end

Чтобы Spring мог управлять приложением, создадим бинарные файлы:

bundle exec spring binstub --all
# отмена изменений
# bin/spring binstub --remove --all

# Перезапускаем сервер
bin/rails restart

Добавление и удаление Spring из бинарных файлов:

bundle exec spring binstub --all
bin/spring binstub --remove --all

Команда bundle exec spring binstub --all добавила в бинарные файлы команд запуск Spring. Пример из bin/rails:

#!/usr/bin/env ruby
# Нижняя строка была добавлена Spring
load File.expand_path("spring", __dir__)
APP_PATH = File.expand_path("../config/application", __dir__)
require_relative "../config/boot"
require "rails/commands"

Строка load File.expand_path("spring", __dir__) загружает Spring, что позволяет ему управлять процессом инициализации приложения. Spring будет следить за изменениями в коде и перезапускать приложение при необходимости.

Логирование

Логирование помогает отслеживать работу приложения, выявлять ошибки и анализировать производительность. Rails предоставляет встроенные механизмы для логирования, которые можно настраивать и расширять в зависимости от потребностей.

Пример логирования в проекте Code Basics:

class ResumeAutoAnswerService
  class << self
    def evaluate_resume(resume)
    # ...
    rescue StandardError => e
      # пишем в лог, если произошлоа ошибка
      Rails.logger.error("#{e.class}: #{e.message}")
      resume.mark_as_failed!
      raise e
    end
end

Rails поддерживает несколько уровней логирования, которые позволяют фильтровать сообщения по важности. В примере выше пишется сообщение уровня error. В Rails доступны следующие уровни логирования:

  • debug: Подробная информация, полезная для отладки.
  • info: Общая информация о работе приложения.
  • warn: Предупреждения о потенциальных проблемах.
  • error: Сообщения об ошибках, которые произошли в приложении.
  • fatal: Критические ошибки, которые могут привести к сбою приложения.
  • unknown: Неизвестный уровень.

Для каждого уровня используются свои методы, предоставляемые Rails. Например:

Rails.logger.debug "Это отладочное сообщение"
Rails.logger.info "Это информационное сообщение"
Rails.logger.warn "Это предупреждение"
Rails.logger.error "Это сообщение об ошибке"
Rails.logger.fatal "Это критическая ошибка"

По умолчанию Rails создает лог-файлы в директории log/ по имени окружения:

  • development.log: Логи для среды разработки.
  • test.log: Логи для тестовой среды.
  • production.log: Логи для производственной среды.

Уровень логирования Rails по умолчанию — debug. Для production-среды в сгенерированном по умолчанию файле config/environments/production.rb указывается info. Этот уровень можно изменить в конфиге окружения изменив config.log_level:

require "active_support/core_ext/integer/time"

Rails.application.configure do
  config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info")
end

Puma

Puma — это высокопроизводительный веб-сервер для Ruby, который часто используется с приложениями на Ruby on Rails. Он поддерживает многопоточность и многопроцессорность, что позволяет эффективно обрабатывать множество запросов одновременно.

Puma используется по умолчанию в Rails. Его настройка может быть выполнена через файл конфигурации config/puma.rb. Пример файла из hexlet-cv:

# config/puma.rb
max_threads_count = ENV.fetch('RAILS_MAX_THREADS', 5)
min_threads_count = ENV.fetch('RAILS_MIN_THREADS') { max_threads_count }
threads min_threads_count, max_threads_count

port ENV.fetch('PORT', 3000)

environment ENV.fetch('RAILS_ENV', 'development')

if ENV.fetch('RENDER', nil)
  pidfile ENV.fetch('PIDFILE', 'tmp/pids/server.pid')
  workers ENV.fetch('WEB_CONCURRENCY', 4)
  preload_app!
end

# Allow puma to be restarted by `rails restart` command.
plugin :tmp_restart

Файл config/puma.rb в приложении Ruby on Rails позволяет настраивать различные параметры веб-сервера Puma, который используется для обработки HTTP-запросов:

  • Количество потоков. Минимальное и максимальное количество потоков, которые Puma будет использовать для обработки запросов. Это позволяет серверу обрабатывать несколько запросов одновременно, что может улучшить производительность приложения.
  max_threads_count = ENV.fetch('RAILS_MAX_THREADS', 5)
  min_threads_count = ENV.fetch('RAILS_MIN_THREADS') { max_threads_count }
  threads min_threads_count, max_threads_count
  • Порт. Порт, на котором Puma будет слушать входящие запросы. Это позволяет изменять порт без необходимости изменения кода.
  port ENV.fetch('PORT', 3000)
  • Среда выполнения. Мы можем установить среду, в которой будет работать Puma (например, development, production, staging и т.д.). Это позволяет вам адаптировать поведение сервера в зависимости от среды.
  environment ENV.fetch('RAILS_ENV', 'development')
  • Рабочие процессы (workers). Мы можем настроить количество воркеров, которые Puma будет использовать для обработки запросов. Это позволяет серверу обрабатывать большее количество запросов одновременно, особенно в средах с высокой нагрузкой.
  workers ENV.fetch('WEB_CONCURRENCY', 4)

Возможности конфигурации этого веб-сервера значительно шире, чем мы рассмотрели. Puma предлагает множество параметров, которые позволяют адаптировать его под специфические требования приложения.

Для более глубокого понимания всех доступных опций и их применения, стоит обратиться к официальной документации Puma. Там можно найти исчерпывающую информацию о всех возможностях настройки.

Заключение

Мы узнали, как правильно работать с окружениями, что позволяет адаптировать приложение к различным условиям, а также рассмотрели использование инициалайзеров для настройки параметров. Мы обсудили важность хранения конфиденциальной информации и познакомились с инструментами, такими как Spring и Puma, которые помогают оптимизировать процесс разработки и развертывания.


Самостоятельная работа

  • Создайте тестовый проект для настройки Rollbar:
  rails new test_rollbar_app
  cd test_rollbar_app
  • Зарегистрируйтесь на Rollbar и создайте в его интерфейсе новый проект
  • Добавьте и установите гем rollbar
  • Сгенерируйте конфигурацию командой
  bin/rails generate rollbar
  • В config/environment.rb добавьте перехват ошибок Rollbar. Полностью файл должен выглядеть так:
  # Load the Rails application.
  require_relative "application"

  # Initialize the Rails application.
  Rails.application.initialize!

  require_relative 'rollbar'

  notify = lambda do |e|
    Rollbar.with_config(use_async: false) do
      Rollbar.error(e)
    end
  rescue StandardError
    Rails.logger.error 'Synchronous Rollbar notification failed.  Sending async to preserve info'
    Rollbar.error(e)
  end

  begin
    Rails.application.initialize!
  rescue Exception => e
    notify.call(e)
    raise
  end
  • Экспортируйте переменную с токеном Rollbar
  export ROLLBAR_ACCESS_TOKEN=<ваш токен>
  • Скопируйте файл rollbar.rb из папки config/initializers в config
  • Запустите приложение. При этом сразу должна появится ошибка:

    Application has been already initialized. (RuntimeError)
    
  • Если Rollbar настроен корректно, то на сайте появится эта ошибка.


Дополнительные материалы

  1. Официальный гайд по Ruby On Rails — Configuring Rails Applications
  2. Devise - гем, предоставляющий возможности для аутентификации в rails-приложениях
  3. Что такое YAML
  4. ENV is a hash-like accessor for environment variables
  5. Официальный гайд по Ruby On Rail - The Logger
  6. Puma
  7. Rails env class

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff