Ответ 1
ActiveRecord (по крайней мере, 3.2.1) обрабатывает пустые массивы как NULL. Заполнители в вызове where
обрабатываются sanitize_sql
. Если вы немного проигнорируете код, вы перейдете к replace_bind_variables
:
def replace_bind_variables(statement, values) #:nodoc:
raise_if_bind_arity_mismatch(statement, statement.count('?'), values.size)
bound = values.dup
c = connection
statement.gsub('?') { quote_bound_value(bound.shift, c) }
end
а затем quote_bound_value
:
def quote_bound_value(value, c = connection) #:nodoc:
if value.respond_to?(:map) && !value.acts_like?(:string)
if value.respond_to?(:empty?) && value.empty?
c.quote(nil)
else
value.map { |v| c.quote(v) }.join(',')
end
else
c.quote(value)
end
end
Пустой массив будет удовлетворять всем четырем условиям, чтобы довести вас до c.quote(nil)
и от того, откуда приходит ваш NULL. Вся специальная логика, которая ведет к c.quote(nil)
, указывает, что это преднамеренное поведение.
Вывод IN (или NOT IN) с пустым списком:
where c in ()
должен вызывать ошибку SQL, поэтому, возможно, люди AR пытаются предотвратить это, спокойно превратив этот плохой SQL в c in (null)
. Обратите внимание, что ни одно из них:
select ... from t where c in (null);
select ... from t where c not in (null);
должен давать какие-либо результаты из-за поведения SQL NULL. Это классическая ошибка новичка, и люди AR действительно должны знать лучше.
Я бы предпочел исключение сам: сказать мне, что я собираюсь развернуть фул-пулю, было бы намного дружелюбно, чем просто передать мне другое оружие.
Исполнительное резюме:
- Это поведение "пустой массив означает, что NULL" преднамеренно.
- Вы никогда не должны пытаться использовать
where('c in (?)', [])
илиwhere('c not in (?)', [])
, поскольку ни один из них не имеет большого смысла. - Обновите свой Ruby-код, чтобы проверить наличие пустых массивов и сделайте все, что нужно сделать, чтобы получить ожидаемые результаты.