`define` и` find` возвращают `nil`, тогда как` find_all` и `select` возвращают результат - PullRequest
0 голосов
/ 01 февраля 2019

С кодом, приведенным ниже, бибуг отключается:

cspg_instance = @game_instances.find do |instance|
  instance_end_time = TimeOperation.new(:+, instance.start_time, instance.duration).result
  if (event.end_time > instance.start_time && event.end_time <= instance_end_time && instance.events.first.period == event.period)
    byebug
  end
end

Это возвращает правильный результат: (edit: этот WAS возвращает правильный результат и теперь возвращает nil)

cspg_instance = @game_instances.find do |instance|
  instance_end_time = TimeOperation.new(:+, instance.start_time, instance.duration).result
  if (event.end_time > instance.start_time && event.end_time <= instance_end_time && instance.events.first.period == event.period)
    ok = true
  end
  ok
end

Тем не менее, он возвращает nil только с условием if (без оператора if);тогда как find_all и select оба возвращают значение.

cspg_instance = @game_instances.find do |instance|
  instance_end_time = TimeOperation.new(:+, instance.start_time, instance.duration).result

  (event.end_time > instance.start_time && event.end_time <= instance_end_time && instance.events.first.period == event.period)
end

Интересно, кто-нибудь знает, что с этим делать;возможно, рубин или сбой установки?

1 Ответ

0 голосов
/ 01 февраля 2019

Есть две разные проблемы:

1) Почему не работает версия с byebug

Это важная часть из документов find: Возвращает первое, для которого блок не является ложным.

Теперь давайте посмотрим на ваши случаи:

# just writing "true" here, with no if statement will deliver a result

Если вы просто напишите true в конце блоказатем возвращается true и, следовательно, find находит эту запись.

if (event.end_time > instance.start_time && event.end_time <= instance_end_time && instance.events.first.period == event.period)
  ok = true
end
ok

Этот случай аналогичен: если условие if равно true, вы присваиваете true okпеременная.Поскольку вы снова вызываете ok в последней строке блока, блок возвращает true и find находит этот элемент.

if (event.end_time > instance.start_time && event.end_time <= instance_end_time && instance.events.first.period == event.period)
  byebug
end

Но этот пример в вашем коде отличается.Здесь вы открываете bundle, если условие if равно true.Это заставляет bundler вызывать последний вызов метода в блоке find.Вызов bundler не возвращает true, поэтому весь блок не возвращает true, а find не выбирает эти записи.

Решение состоит в том, чтобы вернуть true в последнемлиния блока find.Поскольку в вашем коде уже есть условие, вы можете использовать его напрямую, не назначая сначала true переменной.- например, вот так:

cspg_instance = @game_instances.find do |instance|
  instance_end_time = TimeOperation.new(:+, instance.start_time, instance.duration).result

  event.end_time > instance.start_time && event.end_time <= instance_end_time && instance.events.first.period == event.period
end

2) Почему find_all и select работают, а find нет?

В комментариях вы уточнили, что @game_instances на самом деле это не массив, а ActiveRecord::Relation.ActiveRecord::Relation#find работает совершенно иначе, чем метод на Array.Упрощенный find для такого отношения ожидает id записи и возвращает эту запись в объеме, заданном отношением.Вызов to_a для отношения загружает все записи в память и позволяет использовать Array#find.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...