Вопросы на собеседовании: Ruby-разработчик
100 реальных вопросов с образцовыми ответами и пояснениями для уровня Junior Ruby-разработчик.
Смотреть пример резюме: Ruby-разработчик →Тренировка флешкарточками
Интервальное повторение · Hunter Pass
Вопросы
В Ruby каждое значение является объектом, а поведение вызывается через методы.
- 7.class возвращает Integer, а "ruby".class возвращает String.
- Даже операторы являются методами, поэтому 2 + 3 эквивалентно 2.+(3).
- Классы тоже являются объектами, поэтому User.new отправляет метод new объекту User.
Зачем это спрашивают: Интервьюер проверяет, понимаете ли вы единую объектную модель Ruby, а не считаете числа или классы особыми случаями.
Ruby определяет тип объекта во время выполнения, а переменные не имеют фиксированного объявленного типа.
- value может сначала ссылаться на 10, а затем на "ten" без объявления.
- Код может принимать любой объект с методом each вместо проверки точного класса.
- Вызов 10.upcase приводит к NoMethodError во время выполнения, поэтому важны тесты и понятные интерфейсы.
Зачем это спрашивают: Интервьюер проверяет, можете ли вы объяснить и гибкость, и риск ошибок во время выполнения в системе типов Ruby.
В Ruby ложными считаются только false и nil, а любой другой объект является истинным.
- 0, пустой String и пустой Array попадают в истинную ветку if.
- if users.any? проверяет наличие элементов, а if users только проверяет nil или false.
- value || "default" заменяет и nil, и false, поэтому используйте value.nil?, если false имеет смысл.
Зачем это спрашивают: Этот вопрос показывает, не переносит ли кандидат в Ruby неверные представления об истинности из других языков.
Ruby использует префиксы имён, чтобы различать область видимости и принадлежность.
- name является локальной, @name принадлежит одному объекту, а @@count разделяется иерархией классов.
- $stdout является глобальной переменной, а Billing::MAX_RETRIES является константой в пространстве имён.
- Повторное присваивание константе выдаёт предупреждение, но выполняется, а объект по ссылке остаётся изменяемым без freeze.
Зачем это спрашивают: Сильный ответ различает принадлежность переменных и учитывает, что константы не становятся автоматически неизменяемыми.
Метод Ruby возвращает последнее вычисленное выражение, если явно не использован return.
- def double(n); n * 2; end возвращает 8 для double(4).
- Явный return подходит для раннего выхода, например return nil if user.nil?.
- Вопросительный знак в active? является соглашением для предикатов, а не особым синтаксисом возврата.
Зачем это спрашивают: Интервьюер проверяет базовую семантику методов и уместное применение явного return.
Методы Ruby могут сочетать позиционные аргументы, значения по умолчанию и явные именованные аргументы.
- def greet(name, loud = false) имеет один обязательный и один необязательный позиционный аргумент.
- def create(name:, role: "member") требует name: и задаёт role: по умолчанию.
- create(name: "Ira") понятно читается в месте вызова, а отсутствие обязательного ключа приводит к ArgumentError.
Зачем это спрашивают: Сильный ответ показывает актуальный синтаксис именованных аргументов Ruby и ошибку при неверном вызове.
*args собирает дополнительные позиционные аргументы в Array, а **kwargs собирает именованные аргументы в Hash.
- def sum(*numbers) получает sum(1, 2) как [1, 2].
- def build(**options) получает build(color: "red") как { color: "red" }.
- Splat также разворачивает значения, поэтому sum(*[1, 2]) передаёт два позиционных аргумента.
Зачем это спрашивают: Интервьюер проверяет, умеете ли вы собирать и разворачивать аргументы, не смешивая позиционные и именованные данные.
Блок является поведением, переданным методу, а yield выполняет это поведение.
- [1, 2].each { |n| puts n } передаёт блок с параметром n.
- Метод может вызвать yield(value), чтобы передать значение в полученный блок.
- block_given? проверяет наличие блока перед yield и позволяет избежать LocalJumpError.
Зачем это спрашивают: Интервьюер проверяет, понимаете ли вы блоки как переданное поведение, а не только как синтаксис итераторов.
Оба варианта превращают блок в объект, но lambda ведёт себя ближе к методу.
- square = proc { |n| n * n }; square.call(4) возвращает 16.
- Lambda строго проверяет число аргументов, а обычный Proc допускает расхождения.
- return завершает только lambda, но в обычном Proc пытается выйти из окружающего метода.
Зачем это спрашивают: Для джуниора главный сигнал состоит в знании строгой проверки аргументов и поведения return без обсуждения внутреннего устройства.
Enumerable добавляет переиспользуемые методы обхода классу, который выполняет его контракт итерации.
- Класс должен подключить Enumerable через include и определить each, передающий элементы.
- После этого select и map могут фильтровать и преобразовывать переданные значения.
- reduce может объединить значения, например [1, 2, 3].reduce(0, :+) вернёт 6.
Зачем это спрашивают: Интервьюер ожидает обе части контракта Enumerable и конкретные методы, которые он предоставляет.
each обходит элементы, а map строит новый Array из результатов блока.
- [1, 2].each { |n| puts n } выполняет вывод и возвращает исходный Array.
- [1, 2].map { |n| n * 2 } возвращает [2, 4].
- Используйте map для преобразования вместо ручного добавления результатов внутри each.
Зачем это спрашивают: Этот вопрос проверяет, выбираете ли вы метод коллекции по возвращаемому значению и назначению.
Array является упорядоченной коллекцией с индексами от нуля и может хранить объекты разных типов.
- items[0] читает первый элемент, а items[-1] читает последний.
- items << "book" добавляет на месте, а items.pop удаляет и возвращает последний элемент.
- items[1, 2] возвращает срез из двух элементов, начиная с индекса 1.
Зачем это спрашивают: Интервьюер проверяет практическое владение самой распространённой упорядоченной коллекцией Ruby.
Hash хранит пары ключ-значение и возвращает значение по ключу.
- user = { name: "Mina" }; user[:name] возвращает "Mina".
- user[:role] возвращает nil при отсутствии, а user.fetch(:role) вызывает KeyError без значения по умолчанию.
- user.each do |key, value| передаёт обе части каждой пары.
Зачем это спрашивают: Сильный ответ джуниора описывает обычное чтение и более безопасный fetch для обязательных ключей.
Интерполяция вставляет выражение в String с двойными кавычками, а конкатенация соединяет строки.
- "Hello, #{name}" вычисляет name, а одинарные кавычки сохраняют #{name} буквально.
- "Hello, " + name создаёт новый String, а text << name изменяет text.
- При использовании + число требует преобразования, например "Age: " + age.to_s.
Зачем это спрашивают: Интервьюер проверяет синтаксис строк и умение распознавать изменяющие операции.
Symbol является неизменяемым идентификатором, а String представляет изменяемый текст.
- В ключах Hash часто используют символы, например { name: "Ana" }[:name].
- Символы подходят для состояний и ключей опций вроде :pending или :json.
- Пользовательский текст должен оставаться String, а не превращаться в произвольные символы.
Зачем это спрашивают: Хороший ответ выбирает символы по смыслу и неизменяемости, а не называет их более быстрыми строками.
Range представляет интервал, по которому можно итерироваться или проверять принадлежность.
- 1..5 включает 5, а 1...5 исключает 5.
- (18..65).cover?(age) удобно читается как проверка границ.
- array[1..3] использует Range для выбора последовательных элементов.
Зачем это спрашивают: Интервьюер ожидает знание включающей и исключающей форм и одного практического применения.
Изменяющий метод меняет получателя, а неизменяющий возвращает другое значение.
- name.upcase возвращает новый String, а name.upcase! меняет name на месте.
- array.sort возвращает отсортированную копию, а array.sort! переставляет тот же Array.
- Восклицательный знак часто обозначает опасность, но Ruby не навязывает это соглашение.
Зачем это спрашивают: Интервьюер проверяет, можете ли вы предсказать изменение объекта и избежать случайных ошибок с общим состоянием.
freeze запрещает дальнейшую мутацию этого объекта, но защита является поверхностной.
- name = "Ruby".freeze приводит к FrozenError при name << "!".
- Заморозка Array не замораживает изменяемые объекты внутри него.
- frozen? сообщает состояние, а dup обычно создаёт незамороженную поверхностную копию.
Зачем это спрашивают: Интервьюер ожидает практическое назначение защиты и ограничение: freeze не даёт глубокой неизменяемости.
Класс Ruby объединяет поведение, а initialize настраивает каждый новый экземпляр.
- class User; def initialize(name); @name = name; end; end сохраняет переменную экземпляра.
- User.new("Ada") создаёт объект и вызывает initialize.
- attr_reader :name создаёт геттер, не открывая неограниченную запись.
Зачем это спрашивают: Интервьюер проверяет, умеете ли вы создавать инкапсулированный объект, а не открывать всё состояние.
Класс Ruby наследуется от одного суперкласса и может переиспользовать или переопределять его методы.
- class Admin < User объявляет Admin подклассом User.
- Если Admin определяет greet, эта реализация выбирается раньше User#greet.
- super вызывает следующую реализацию; super передаёт текущие аргументы, а super() не передаёт их.
Зачем это спрашивают: Сильный ответ джуниора объясняет одиночное наследование и передачу аргументов через super.
Закрытые вопросы
- 21
Для чего используют модули и mixin?
modules - 22
Что означают public, protected и private в Ruby?
ruby - 23
Чем методы экземпляра отличаются от методов класса?
- 24
Как обрабатывать исключения в Ruby?
error-handlingrubysoft-skills - 25
Как безопасно читать и записывать файлы в Ruby?
ruby - 26
Как вместе работают require, RubyGems и Bundler?
bundlinggems - 27
Чем отличаются ==, eql? и equal? в Ruby?
ruby - 28
Как if, unless и case выражают условия?
- 29
Что делает оператор безопасной навигации?
- 30
Как Ruby ищет вызываемый метод?
ruby - 31
Что относится к Model, View и Controller в MVC Rails?
rails - 32
Как роутинг Rails связывает URL с действием?
rails - 33
Что должно делать базовое действие контроллера Rails?
rails - 34
Что такое strong parameters?
- 35
Что такое модель ActiveRecord?
orm - 36
Как работают валидации моделей Rails?
validationrails - 37
Что такое миграция базы данных Rails?
databasemigrationsrails - 38
Как работают belongs_to и has_many?
- 39
Как выполнять базовые CRUD-операции через ActiveRecord?
orm - 40
Чем отличаются where, find_by и find?
- 41
Что такое scope в ActiveRecord?
orm - 42
Что такое проблема N+1 запросов в Rails?
queriesn+1rails - 43
Как ресурсные маршруты сопоставляются с REST-действиями?
rest - 44
Какие HTTP-коды должен возвращать базовый Rails API?
httpstatus-codesrails - 45
Как ERB-представление рендерит данные контроллера?
- 46
Что такое partial в Rails и как работают locals?
rails - 47
Для чего полезна Rails console?
rails - 48
Чем отличаются окружения Rails?
rails - 49
Как написать базовый пример RSpec для модели?
testing - 50
Что должна проверять request spec RSpec?
testing - 51
user.name вызывает NoMethodError, потому что user равен nil. Как искать причину?
- 52
Необязательный профиль приводит к падению user.profile.city. Какое небольшое исправление внести?
- 53
Почему {"name" => "Ana"}[:name] возвращает nil и как это исправить?
- 54
После copy = original.dup изменение copy[:settings][:theme] меняет и original. Почему?
- 55
Метод должен удвоить массив без изменения входа, но использует map!. Как исправить?
- 56
Как должен вести себя пользовательский EventLog#each, если вызывающий код не передал блок?
blocks - 57
Почему def calculate; yield(4); 10; end возвращает 10, если блок вернул 8?
blocks - 58
Что вернёт formatter = proc { |name| name.strip.upcase } для formatter.call(" Ada ")?
blocks - 59
Почему Proc, созданный внутри build_formatter, помнит локальный prefix после завершения build_formatter?
blocks - 60
Что вернёт [1, 2, 3, 4].select(&:even?).map { |n| n * 10 }?
- 61
Нужно найти первого активного администратора в массиве. Почему лучше find или detect, а не select.first?
- 62
В CSV-импорте нет обязательных заголовков. Как сообщить об этом ожидаемом сбое своим исключением?
error-handling - 63
CSV.parse(File.read(path)) вызывает invalid byte sequence in UTF-8 для клиентского файла, хотя File.read выполнился успешно. Как обработать файл?
soft-skills - 64
Обёртка API логирует таймаут, а вызывающий код считает запрос успешным. Чего не хватает?
resilienceapi - 65
File.read("config/settings.json") работает локально, но в тестах даёт Errno::ENOENT. Что проверить?
config - 66
require "csv_importer" даёт LoadError, хотя файл есть в lib/. Что проверить?
- 67
Приложение падает с Bundler::GemNotFound. Каковы первые проверки?
bundlinggems - 68
Bundler сообщает: gem A требует Rack ниже 3, а gem B требует Rack 3+. Что делать?
bundlinggemsrack - 69
RSpec сообщает expected: 201, got: 422. Как использовать этот вывод?
testing - 70
Спека проходит отдельно, но находит двух пользователей в полном наборе. Что проверить?
- 71
После merge Git показывает маркеры конфликта в orders_controller.rb. Что делать?
git - 72
Вы слили не ту ветку и ещё не закоммитили конфликтный merge. Что безопасно сделать?
- 73
Rails возвращает 404 для /orders/42, но OrdersController#show существует. Что проверить первым?
rails - 74
GET /orders работает, но форма получает ошибку маршрута для POST /orders. Почему?
forms - 75
Rails пишет Unpermitted parameter: :role, и role не меняется. Как реагировать?
rails - 76
User.create(email: "bad") возвращает несохранённый объект. Как найти ошибку валидации?
validation - 77
Когда при отладке записи Rails использовать save! вместо save?
rails - 78
post.author.name падает для одной записи при belongs_to :author. Что исследовать?
- 79
Как смоделировать участие пользователей во многих проектах, если каждая связь хранит ещё и роль участника?
- 80
После получения кода Rails даёт PG::UndefinedColumn для orders.status. Что проверить?
railsfundamentals - 81
Конкретная локальная миграция добавила неверный столбец, но после неё уже выполнились новые миграции. Как отменить только её?
migrationsschema - 82
Почему Order.where(status: "paid") не показывает SQL до вызова to_a?
sql - 83
Задача обслуживания должна обработать 200 000 активных пользователей. Как не загружать их всех сразу?
concurrency - 84
Дашборду нужно только число активных пользователей. Почему стоит вызвать User.active.count вместо User.active.to_a.length?
- 85
Вы добавили includes(:author), но страница всё ещё медленная. Какие данные собрать?
- 86
Несколько Rails view повторяют order.created_at.strftime("%d %b %Y"). Куда вынести форматирование?
rails - 87
Почему form_with model: @article на странице редактирования отправляет PATCH /articles/7, а не POST /articles?
- 88
Rails-запрос возвращает 500 только для одного payload. Как логи сузят ошибку?
rails - 89
Как экспериментировать с обновлениями моделей в Rails console без сохранения изменений базы?
experimentsdatabaserails - 90
GET /articles возвращает все 10 000 строк и расходует слишком много памяти. Какую базовую пагинацию добавить?
memorypagination - 91
Отсутствующий API-ресурс превращается в 500. Как исправить ответ?
api - 92
Order#subtotal суммирует произведения количества и цены каждой позиции. Как протестировать этот обычный метод модели?
- 93
Request spec ожидает JSON от POST /orders, но response.parsed_body падает, потому что контроллер вернул HTML redirect. Что вы проверите?
html - 94
Sidekiq job остаётся в очереди, а worker пишет Redis::CannotConnectError. Что проверить?
redisdata-structuresbackground-jobs - 95
Что произойдёт при вызове ReportJob.perform_async(user) с объектом User в нативном Sidekiq и что нужно передать?
background-jobs - 96
Повторная Sidekiq job дважды добавляет 10 кредитов. Как сделать её идемпотентной?
background-jobsidempotency - 97
Turbo-ссылка заменяет всю страницу вместо frame comments. Что проверить?
- 98
Опишите успешный HTML-запрос Rails GET /products/7.
htmlrails - 99
PostgreSQL даёт PG::NotNullViolation, когда у заказа нет currency. Как исправить?
postgres - 100
Удаление пользователя вызывает PG::ForeignKeyViolation, потому что заказы всё ещё ссылаются на него. Что проверить до изменения constraint?